문제
다음과 같은 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>
사용에 주목하십시오:
그만큼 그룹화를위한 무처리 방법
XSLT 엔진에 따라 다릅니다. 확장없이 XSLT 1.0을 사용하는 경우 접근 방식이 최고입니다.
다른 한편으로, Exslt (특히 노드 세트 확장자) 또는 XSLT 2.0을 사용할 수 있으면보다 일반적인 방식으로 수행 할 수 있습니다.
- 사용 가능한 모든 상태를 수집하십시오
- 얻은 결과에서 노드 세트를 만듭니다
- 이 노드 세트를 반복하려면 반복의 현재 요소의 상태베이스를 필터링하여 피벗을 만듭니다.
그러나 그렇게하기 전에, 몇 가지 상태 만 있고 다른 상태를 추가하는 것은 매우 드 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>
제휴하지 않습니다 StackOverflow