당신은 지역의 이름과 값, 그리고 (다시 로컬 이름과 문자열 값으로) 모든 아이들 요소의 모든 속성을 분류하고 .
지금까지 그렇게 좋았습니다.
당신이 직면하는 어려움 중 하나는 "속성 이름"을 기준으로 정렬한다는 것입니다. 당신이 알파벳 순서로 자신의 속성 이름의 목록으로 분류 요소를 원하는 것처럼 당신의 노드 그룹 요소의 자식에 대한 정렬 키
'NodeC', 'asc name', '2 z', 103
'NodeC', 'name', 'a', 102
'NodeC', 'name', 'b', 201
것을 다음 어려움이 전혀 거기되도록 귀하의 예제에서, 그것은 보지 않는다 컨텍스트 노드로 NodeGroup 요소의 첫 번째 NodeC를 사용하여 XPath 1.0 표현식에서 'asc name'값을 가져 오는 확실한 방법입니다. 물론 문자열을 생성 할 수도 있지만 명명 된 템플릿을 호출해야합니다. (또는, 더 정확하게는 : 나는 그런 전화없이 생성하는 방법을 볼 수 없습니다.)
XSLT 2.0 솔루션 문제는 XSLT 2.0의 비교적 간단
;
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*">
<xsl:sort select="local-name()"/>
<xsl:sort select="."/>
</xsl:apply-templates>
<xsl:apply-templates select="node()">
<xsl:sort select="local-name()"/>
<xsl:sort select="string-join(local:key2(.), ' ')"/>
<xsl:sort select="string-join(local:key3(.), ' ')"/>
<xsl:sort select="." data-type="number"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:function name="local:key2" as="xs:string*">
<xsl:param name="e" as="node()"/>
<xsl:for-each select="$e/@*">
<xsl:sort select="local-name()"/>
<xsl:sort select="string()"/>
<xsl:value-of select="local-name()"/>
</xsl:for-each>
</xsl:function>
<xsl:function name="local:key3" as="xs:string*">
<xsl:param name="e" as="node()"/>
<xsl:for-each select="$e/@*">
<xsl:sort select="local-name()"/>
<xsl:sort select="string()"/>
<xsl:value-of select="string()"/>
</xsl:for-each>
</xsl:function>
이러한 일반적인 접근법은 또한 사용자 정의 기능에 대한 EXSLT 확장자 XSLT 1.0에서 사용될 수있다 : 다음 단편 중요한 비트를 나타낸다. EXSLT 기능
당신의 XSLT의 경우와 XSLT 1.0
솔루션 1.0 프로세서가 EXSLT 스타일의 사용자 정의 기능을 지원합니다, 당신은 XSLT 1.0에서 비슷한 일을 할 수 있습니다. (내 최초의 시도는 실패하지만 스타일 시트 요소에 extension-element-prefixes
속성을 추가 기억 할 때 오류가 사라졌다.)
xsltproc하여 입력에서 실행 <xsl:stylesheet version="1.0"
extension-element-prefixes="func"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:func="http://exslt.org/functions"
xmlns:local="http://example.com/nss/dummy">
<xsl:output encoding="utf-8"
method="xml"
omit-xml-declaration="yes"
indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*">
<xsl:sort select="local-name()"/>
<xsl:sort select="."/>
</xsl:apply-templates>
<xsl:apply-templates select="node()">
<xsl:sort select="local-name()"/>
<xsl:sort select="local:key2(.)"/>
<xsl:sort select="local:key3(.)"/>
<xsl:sort select="." data-type="number"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<func:function name="local:key2">
<xsl:param name="e" select="."/>
<func:result>
<xsl:for-each select="$e/@*">
<xsl:sort select="local-name()"/>
<xsl:sort select="string()"/>
<xsl:value-of select="concat(local-name(), ' ')"/>
</xsl:for-each>
</func:result>
</func:function>
<func:function name="local:key3">
<xsl:param name="e" select="."/>
<func:result>
<xsl:for-each select="$e/@*">
<xsl:sort select="local-name()"/>
<xsl:sort select="string()"/>
<xsl:value-of select="concat(string(), ' ')"/>
</xsl:for-each>
</func:result>
</func:function>
</xsl:stylesheet>
이 원하는 출력을 생성합니다.
노드 집합 확장을 사용하여 XSLT 1.0에서 영리한 작업을 수행 할 수도 있습니다.
확장되지 않은 XSLT 1의 2 단계 파이프 라인.0
그러나 확장되지 않은 XSLT 1.0에서이 문제를 해결하는 가장 간단한 방법은 두 개의 스타일 시트를 파이프 라인으로 연결하는 것입니다. 첫 번째 정렬 키가 2, 3 제공하는 모든 요소에 두 개의 속성을 추가한다 (그들이 당신이 원하는 것을 할 수 있도록 명명 된 템플릿을 조정합니다.) 난을 줄이기 위해 네임 스페이스에 넣어 한
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:PJ="http://example.com/PankajJaju">
<xsl:output encoding="utf-8"
method="xml"
omit-xml-declaration="yes"
indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:if test="self::*">
<xsl:attribute name="PJ:attribute-names"
namespace="http://example.com/PankajJaju">
<xsl:call-template name="attribute-name-list"/>
</xsl:attribute>
<xsl:attribute name="PJ:attribute-values"
namespace="http://example.com/PankajJaju">
<xsl:call-template name="attribute-value-list"/>
</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<xsl:template name="attribute-name-list">
<xsl:for-each select="@*">
<xsl:sort select="local-name()"/>
<xsl:sort select="string()"/>
<xsl:value-of select="concat(local-name(), ' ')"/>
</xsl:for-each>
</xsl:template>
<xsl:template name="attribute-value-list">
<xsl:for-each select="@*">
<xsl:sort select="local-name()"/>
<xsl:sort select="string()"/>
<xsl:value-of select="concat(string(), ' ')"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
이름 충돌의 가능성.
두 번째 것은 정렬 키를 사용하여 실제 정렬을 수행하고 임시 속성을 억제합니다.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:PJ="http://example.com/PankajJaju">
<xsl:output encoding="utf-8"
method="xml"
omit-xml-declaration="yes"
indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*">
<xsl:sort select="local-name()"/>
<xsl:sort select="."/>
</xsl:apply-templates>
<xsl:apply-templates select="node()">
<xsl:sort select="local-name()"/>
<xsl:sort select="@PJ:attribute-names"/>
<xsl:sort select="@PJ:attribute-values"/>
<xsl:sort select="."/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="@PJ:attribute-names | @PJ:attribute-values"/>
</xsl:stylesheet>
이들은 원하는 기술을 사용하여 파이프 라인 될 수 있습니다. ...
xsltproc p1.xsl input.xml | xsltproc p2.xsl -
을 예를 들어, bash는 명령 줄에서 xsltproc을 사용하고, 파이프 라인 스타일 1과 2에 이름 p1.xsl 및 p2.xsl을 할당 이것은 당신이 싶은 말은 출력을 생성합니다.
'NodeGroup/NodeC' 요소가'name' 속성의'a','b','z' 값에 따라 정렬되므로 원하는 결과가 속성 값에 따라 어떻게 정렬되는지 알 수 있습니다. 또한,'NodeA' 엘리먼트는'class' 애트리뷰트의'1','3' 값에 의해 정렬됩니다. 'NodeB/NodeC' 요소 (속성 없음)가'101','103' 값으로 정렬되기 때문에 노드 값별로 정렬되는 방법을 볼 수 있습니다. 그러나 출력이 노드 이름 또는 속성 이름별로 어떻게 정렬되는지는 알 수 없습니다. –
요소에 둘 이상의 속성이있는 경우 어떻게 될 것으로 예상됩니까? –
@BenL - 더 나은 샘플 xml로 질문 업데이트 –