development

XSLT : 동안 속성 값을 변경하는 방법

big-blog 2020. 12. 29. 08:20
반응형

XSLT : 동안 속성 값을 변경하는 방법 ?


XML 문서가 있고 속성 중 하나의 값을 변경하려고합니다.

먼저 다음을 사용하여 입력에서 출력으로 모든 것을 복사했습니다.

<xsl:template match="@*|node()">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
</xsl:template>

이제 "type"라는 요소 의 속성 값을 변경하고 싶습니다 "property".


간단한 예제에서 테스트되었으며 잘 작동합니다.

<xsl:template match="@*|node()">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
</xsl:template>
<xsl:template match="@type[parent::property]">
  <xsl:attribute name="type">
    <xsl:value-of select="'your value here'"/>
  </xsl:attribute>
</xsl:template>

Tomalak의 제안을 포함하도록 편집되었습니다.


이 문제에는 고전적인 해결책이 있습니다 . ID 템플릿을 사용하고 재정의 하는 것은 가장 기본적이고 강력한 XSLT 디자인 패턴 중 하나입니다 .

<xsl:stylesheet version="1.0" 
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

    <xsl:param name="pNewType" select="'myNewType'"/>

    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="property/@type">
        <xsl:attribute name="type">
            <xsl:value-of select="$pNewType"/>
        </xsl:attribute>
    </xsl:template>
</xsl:stylesheet>

이 XML 문서에 적용되는 경우 :

<t>
  <property>value1</property>
  <property type="old">value2</property>
</t>

원하는 결과가 생성됩니다 .

<t>
  <property>value1</property>
  <property type="myNewType">value2</property>
</t>

루트 요소에 xmlns 정의가 있으면 상위 두 가지 답변이 작동하지 않습니다.

<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml">
    <property type="old"/>
</html>

위의 xml에서는 모든 솔루션이 작동하지 않습니다.

가능한 해결책은 다음과 같습니다.

<?xml version="1.0"?> 

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:template match="node()[local-name()='property']/@*[local-name()='type']">
      <xsl:attribute name="{name()}" namespace="{namespace-uri()}">
                some new value here
          </xsl:attribute>
  </xsl:template>

  <xsl:template match="@*|node()|comment()|processing-instruction()|text()">
      <xsl:copy>
          <xsl:apply-templates select="@*|node()|comment()|processing-instruction()|text()"/>
      </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

대상 속성과 일치하는 템플릿이 필요합니다.

<xsl:template match='XPath/@myAttr'>
  <xsl:attribute name='myAttr'>This is the value</xsl:attribute>
</xsl:template>

이것은 이미 가지고있는 "모두 복사"에 추가 된 것입니다 (실제로 항상 XSLT에 기본적으로 존재합니다). 보다 구체적인 일치가 있으면 우선적으로 사용됩니다.


간단한 노드에서 하나의 속성을 삭제하고 싶은 비슷한 경우가 있었는데 어떤 축이 속성 이름을 읽을 수 있는지 알아낼 수 없었습니다. 결국 제가해야 할 일은

@*[name(.)!='AttributeNameToDelete']


다음 XML의 경우 :

<?xml version="1.0" encoding="utf-8"?>
<root>
    <property type="foo"/>
    <node id="1"/>
    <property type="bar">
        <sub-property/>
    </property>
</root>

다음 XSLT에서 작동하도록 할 수있었습니다.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="//property">
        <xsl:copy>
            <xsl:attribute name="type">
                <xsl:value-of select="@type"/>
                <xsl:text>-added</xsl:text>
            </xsl:attribute>
            <xsl:copy-of select="child::*"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

소스 XML 문서에 자체 네임 스페이스가있는 경우 스타일 시트에서 네임 스페이스를 선언하고 접두사를 할당 한 다음 소스 XML의 요소를 참조 할 때 해당 접두사를 사용해야합니다. 예를 들면 다음과 같습니다.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xhtml="http://www.w3.org/1999/xhtml">

<xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes" />

<!-- identity transform -->
<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
</xsl:template>

<!-- exception-->    
<xsl:template match="xhtml:property/@type">
    <xsl:attribute name="type">
        <xsl:text>some new value</xsl:text> 
    </xsl:attribute>
</xsl:template>

</xsl:stylesheet>

또는 원하는 경우 :

...
<!-- exception-->    
<xsl:template match="@type[parent::xhtml:property]">
  <xsl:attribute name="type">
        <xsl:text>some new value</xsl:text> 
  </xsl:attribute>
</xsl:template>
...

ADDENDUM: In the highly unlikely case where the XML namespace is not known beforehand, you could do:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes" />

<!-- identity transform -->
<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
</xsl:template>

<!-- exception -->
<xsl:template match="*[local-name()='property']/@type">
    <xsl:attribute name="type">
        <xsl:text>some new value</xsl:text> 
    </xsl:attribute>
</xsl:template>

Of course, it's very difficult to imagine a scenario where you would know in advance that the source XML document contains an element named "property", with an attribute named "type" that needs replacing - but still not know the namespace of the document. I have added this mainly to show how your own solution could be streamlined.


I also came across same issue and i solved it as follows:

<!-- identity transform -->
<xsl:template match="@*|node()">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
</xsl:template>

<!-- copy property element while only changing its type attribute -->
<xsl:template match="property">
  <xsl:copy>
    <xsl:attribute name="type">
      <xsl:value-of select="'your value here'"/>
    </xsl:attribute>
    <xsl:apply-templates select="@*[not(local-name()='type')]|node()"/>
  <xsl:copy>
</xsl:template>

ReferenceURL : https://stackoverflow.com/questions/615875/xslt-how-to-change-an-attribute-value-during-xslcopy

반응형