문제

다음과 같은 XML 파일이 있습니다.

<root>
    <item>
        <name>one</name>
        <status>good</status>
    </item>
    <item>
        <name>two</name>
        <status>good</status>
    </item>
    <item>
        <name>three</name>
        <status>bad</status>
    </item>
    <item>
        <name>four</name>
        <status>ugly</status>
    </item>
    <item>
        <name>five</name>
        <status>bad</status>
    </item>
</root>

XSLT를 사용하여 이것을 변환하여 다음과 같은 것을 얻고 싶습니다.

<root>
    <items><status>good</status>
        <name>one</name>
        <name>two</name>
    </items>
    <items><status>bad</status>
        <name>three</name>
        <name>five</name>
    </items>
    <items><status>ugly</status>
        <name>four</name>
    </items>
</root>

다시 말해, 각각 상태가있는 항목 목록을 얻고 각각 항목 목록이있는 상태 목록으로 바꾸고 싶습니다.

나의 초기 생각은 각 상태 유형과 차례로 일치하는 신청서를 수행하는 것이었지만, 이는 전체 상태 목록을 알아야한다는 것을 의미합니다. 더 좋은 방법이 있습니까?

도움을 주셔서 감사합니다.

도움이 되었습니까?

해결책

구조에 뮤을!

<?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" indent="yes" encoding="UTF-8"/>

    <xsl:key name="muench" match="/root/item/status" use="."/>

    <xsl:template match="/">
        <root>
        <xsl:for-each select="/root/item/status[generate-id() = generate-id(key('muench',.)[1])]">
            <xsl:call-template name="pivot">
                <xsl:with-param name="status" select="."/>
            </xsl:call-template>
        </xsl:for-each>
        </root>
    </xsl:template>

    <xsl:template name="pivot">
        <xsl:param name="status"/>
        <items>
            <status><xsl:value-of select="$status"/></status>
            <xsl:for-each select="/root/item[status=$status]">
                <name><xsl:value-of select="name"/></name>
            </xsl:for-each>
        </items>
    </xsl:template>

</xsl:stylesheet>

다른 팁

예, 이것은 XSLT 1.0에서 수행 할 수 있습니다

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 >
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <!--                                   -->
    <xsl:key name="kStatByVal" 
         match="status" use="."/>
    <!--                                   -->
    <xsl:key name="kItemByStat" 
         match="item" use="status"/>
    <!--                                   -->
    <xsl:variable name="vDoc" select="/"/>

    <xsl:template match="/">
      <top>
        <xsl:for-each select=
        "/*/*/status[generate-id()
                    =
                     generate-id(key('kStatByVal',.)[1])
                    ]">
          <items>
            <status><xsl:value-of select="."/></status>
          <xsl:for-each select="key('kItemByStat', .)">
            <xsl:copy-of select="name"/>
          </xsl:for-each>
          </items>
        </xsl:for-each>
      </top>
    </xsl:template>
</xsl:stylesheet>

이 변환이 원본 XML 문서에 적용될 때:

<root>
    <item>
        <name>one</name>
        <status>good</status>
    </item>
    <item>
        <name>two</name>
        <status>good</status>
    </item>
    <item>
        <name>three</name>
        <status>bad</status>
    </item>
    <item>
        <name>four</name>
        <status>ugly</status>
    </item>
    <item>
        <name>five</name>
        <status>bad</status>
    </item>
</root>

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

<top>
    <items>
        <status>good</status>
        <name>one</name>
        <name>two</name>
    </items>
    <items>
        <status>bad</status>
        <name>three</name>
        <name>five</name>
    </items>
    <items>
        <status>ugly</status>
        <name>four</name>
    </items>
</top>

사용에 주목하십시오:

  1. 그만큼 그룹화를위한 무처리 방법

  2. 사용 <xsl:key> 그리고 key() 기능

XSLT 엔진에 따라 다릅니다. 확장없이 XSLT 1.0을 사용하는 경우 접근 방식이 최고입니다.

다른 한편으로, Exslt (특히 노드 세트 확장자) 또는 XSLT 2.0을 사용할 수 있으면보다 일반적인 방식으로 수행 할 수 있습니다.

  1. 사용 가능한 모든 상태를 수집하십시오
  2. 얻은 결과에서 노드 세트를 만듭니다
  3. 이 노드 세트를 반복하려면 반복의 현재 요소의 상태베이스를 필터링하여 피벗을 만듭니다.

그러나 그렇게하기 전에, 몇 가지 상태 만 있고 다른 상태를 추가하는 것은 매우 드 rare다면 과잉 일 수 있다고 생각하십시오.

XSLT 2.0에서는 표준 그룹화 메커니즘으로 Muenchian 그룹을 교체 할 수 있습니다. 주어진 답변에 적용된 XSLT는 다음과 같습니다.

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

    <xsl:output method="xml" indent="yes" encoding="UTF-8"/>

    <xsl:key name="muench" match="/root/item/status" use="."/>

    <xsl:template match="/">
        <root>
        <xsl:for-each-group select="/root/item/status" group-by="key('muench', .)">
            <xsl:call-template name="pivot">
                <xsl:with-param name="status" select="."/>
            </xsl:call-template>
        </xsl:for-each-group>
        </root>
    </xsl:template>

    <xsl:template name="pivot">
        <xsl:param name="status"/>
        <items>
            <status><xsl:value-of select="$status"/></status>
            <xsl:for-each select="/root/item[status=$status]">
                <name><xsl:value-of select="name"/></name>
            </xsl:for-each>
        </items>
    </xsl:template>

</xsl:stylesheet>
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top