I have an input XML file which I need to copy 1:1 to the output, except for one subelement which contains subitems that need to be sorted.
我有一个输入XML文件,我需要将它1:1复制到输出,除了一个包含需要排序的子项的子元素。
<?xml version="1.0"?>
<top>
<elementA />
<elementB />
<contents>
<contentitem>
<id>3</id>
<moretags1 />
<moretags2 />
</contentitem>
<contentitem>
<id>2</id>
<moretags1 />
<moretags2 />
</contentitem>
<contentitem>
<id>1</id>
<moretags1 />
<moretags2 />
</contentitem>
</contents>
</top>
I'd like an XSL Transformation that puts the "contentitem" elements in order, sorted by their "id" elements. All other tags, including nested ones, must be copied verbatim. I already tried with xsl:copy, but either I get double contents or something turns out missing.
我想要一个XSL转换,它将“contentiem”元素按其“id”元素排序。所有其他标记(包括嵌套标记)必须逐字复制。我已经尝试过xsl:copy,但是要么得到双重内容,要么发现缺少某些内容。
3 个解决方案
#1
7
Mark Gravell's solution is almost correct -- with a slight issue that creates two nested <contents>
elements. Note to all who provide answers: Do test your solutions!
Mark Gravell的解决方案几乎是正确的——有一个小问题创建了两个嵌套的
Here is a correct solution. This transformation:
这里有一个正确的解决方法。这一转变:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<!-- -->
<xsl:strip-space elements="*"/>
<!-- -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<!-- -->
<xsl:template match="contents">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="contentitem">
<xsl:sort select="id" data-type="number"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
when applied on the originally-provided XML document:
当应用于原始提供的XML文档时:
<top>
<elementA />
<elementB />
<contents>
<contentitem>
<id>3</id>
<moretags1 />
<moretags2 />
</contentitem>
<contentitem>
<id>2</id>
<moretags1 />
<moretags2 />
</contentitem>
<contentitem>
<id>1</id>
<moretags1 />
<moretags2 />
</contentitem>
</contents>
</top>
produces the wanted, correct result:
产生想要的、正确的结果:
<top>
<elementA/>
<elementB/>
<contents>
<contentitem>
<id>1</id>
<moretags1/>
<moretags2/>
</contentitem>
<contentitem>
<id>2</id>
<moretags1/>
<moretags2/>
</contentitem>
<contentitem>
<id>3</id>
<moretags1/>
<moretags2/>
</contentitem>
</contents>
</top>
Do note the following:
请注意以下:
-
The use of the identity rule to copy all nodes without change.
使用标识规则复制所有节点而不进行更改。
-
How the identity template is overriden with a specific template matching the
contents
element标识模板是如何使用与内容元素匹配的特定模板来覆盖的?
-
The use of the
<xsl:sort>
instruction to present the results of applying a template in a specific order, possibly different from the document order of the nodes, selected for processing.使用
指令以特定顺序(可能与节点的文档顺序不同)表示应用模板的结果。
#2
2
How about:
如何:
<?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"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/top/contents">
<contents>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="contentitem">
<xsl:sort data-type="number" select="id"/>
</xsl:apply-templates>
</xsl:copy>
</contents>
</xsl:template>
</xsl:stylesheet>
#3
0
Use xsl:sort with either xsl:for-each or xsl:apply-templates
使用xsl:对每个或xsl:apply模板进行排序。
Something like
类似的
<xsl:template match='/top/contents'>
<xsl:apply-templates select='contentitem'>
<xsl:sort select='id' data-type='number'/>
</xsl:apply-templates>
</xsl:template>
Multiple xsl:sort elements can be used for multiple sort keys.
多个xsl:sort元素可以用于多个排序键。
#1
7
Mark Gravell's solution is almost correct -- with a slight issue that creates two nested <contents>
elements. Note to all who provide answers: Do test your solutions!
Mark Gravell的解决方案几乎是正确的——有一个小问题创建了两个嵌套的
Here is a correct solution. This transformation:
这里有一个正确的解决方法。这一转变:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<!-- -->
<xsl:strip-space elements="*"/>
<!-- -->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<!-- -->
<xsl:template match="contents">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="contentitem">
<xsl:sort select="id" data-type="number"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
when applied on the originally-provided XML document:
当应用于原始提供的XML文档时:
<top>
<elementA />
<elementB />
<contents>
<contentitem>
<id>3</id>
<moretags1 />
<moretags2 />
</contentitem>
<contentitem>
<id>2</id>
<moretags1 />
<moretags2 />
</contentitem>
<contentitem>
<id>1</id>
<moretags1 />
<moretags2 />
</contentitem>
</contents>
</top>
produces the wanted, correct result:
产生想要的、正确的结果:
<top>
<elementA/>
<elementB/>
<contents>
<contentitem>
<id>1</id>
<moretags1/>
<moretags2/>
</contentitem>
<contentitem>
<id>2</id>
<moretags1/>
<moretags2/>
</contentitem>
<contentitem>
<id>3</id>
<moretags1/>
<moretags2/>
</contentitem>
</contents>
</top>
Do note the following:
请注意以下:
-
The use of the identity rule to copy all nodes without change.
使用标识规则复制所有节点而不进行更改。
-
How the identity template is overriden with a specific template matching the
contents
element标识模板是如何使用与内容元素匹配的特定模板来覆盖的?
-
The use of the
<xsl:sort>
instruction to present the results of applying a template in a specific order, possibly different from the document order of the nodes, selected for processing.使用
指令以特定顺序(可能与节点的文档顺序不同)表示应用模板的结果。
#2
2
How about:
如何:
<?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"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/top/contents">
<contents>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="contentitem">
<xsl:sort data-type="number" select="id"/>
</xsl:apply-templates>
</xsl:copy>
</contents>
</xsl:template>
</xsl:stylesheet>
#3
0
Use xsl:sort with either xsl:for-each or xsl:apply-templates
使用xsl:对每个或xsl:apply模板进行排序。
Something like
类似的
<xsl:template match='/top/contents'>
<xsl:apply-templates select='contentitem'>
<xsl:sort select='id' data-type='number'/>
</xsl:apply-templates>
</xsl:template>
Multiple xsl:sort elements can be used for multiple sort keys.
多个xsl:sort元素可以用于多个排序键。