XML - XSLT - for-each 按元素位置排序
XML - XSLT - for-each ordered by element position
我有以下 XML 文档:
<?xml version="1.0" encoding="utf-8" ?>
<doc>
<order>
<oField name="YEAR"></oField>
<oField name="MONTH"></oField>
<oField name="DAY"></oField>
</order>
<noOrder>
<noField name="MONTH"></noField>
<noField name="YEAR"></noField>
<noField name="DAY"></noField>
</noOrder>
</doc>
我想做的是创建一个新元素,它是 order
和 noOrder
的同级元素,它基本上从 noField
元素中获取属性,但打印它们基于在上部 order
元素中的顺序。也许我很困惑,但这是我想要得到的结果 XML 文档:
<?xml version="1.0" encoding="UTF-8"?>
<doc>
<order>
<oField name="YEAR"/>
<oField name="MONTH"/>
<oField name="DAY"/>
</order>
<noOrder>
<noField name="MONTH"/>
<noField name="YEAR"/>
<noField name="DAY"/>
</noOrder>
<newOrder>
<newOField>YEAR</newOField>
<newOField>MONTH</newOField>
<newOField>DAY</newOField>
</newOrder>
</doc>
请注意 oField
和 noField
元素的属性 name
将相同,但我不想从 [=20= 获取数据] 元素,这些元素已经被订购。我想从noField
个元素中获取,
这是我目前拥有的 XSLT 代码:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0">
<xsl:output indent="yes" cdata-section-elements="xml-property"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="doc/noOrder">
<xsl:next-match/>
<newOrder>
<xsl:for-each select="noField">
<!--<xsl:sort select="/doc/order/oField[position()]"/>-->
<newOField>
<xsl:value-of select="@name"/>
</newOField>
</xsl:for-each>
</newOrder>
</xsl:template>
</xsl:stylesheet>
产生以下结果:
<?xml version="1.0" encoding="UTF-8"?>
<doc>
<order>
<oField name="YEAR"/>
<oField name="MONTH"/>
<oField name="DAY"/>
</order>
<noOrder>
<noField name="MONTH"/>
<noField name="YEAR"/>
<noField name="DAY"/>
</noOrder>
<newOrder>
<newOField>MONTH</newOField>
<newOField>YEAR</newOField>
<newOField>DAY</newOField>
</newOrder>
</doc>
正如您在我的 XSLT 代码的注释行中看到的那样,我尝试将 xsl:sort
元素设置为按 oField
元素排序,但由于其中有三个元素,/doc/order/oField[position()]
returns 多个值并且无法完成排序(这就是注释该行的原因)
简单的解决方案是通过 oField
元素设置 xsl:for-each
,但正如我之前所说,这不是我想要的,
XSLT 中有没有办法做到这一点?
谢谢!
EDIT/UPDATE
也许我写问题的方式有点混乱,但我想从元素中的属性中获取数据,而不是从元素中获取数据。但是因为它们是相同的(并且元素完全相同,具有相同的属性值),我想按照它们在元素中出现的顺序打印属性中的值(在元素中,在元素内部)
谢谢!
亚历山大·哈辛托
我不确定我是否正确理解了你的问题。
试试下面的模板,输出是你想要的。它使用 noField
的 position()
作为 oField
的索引并打印其 @name
属性。
<xsl:template match="doc/noOrder">
<xsl:next-match/>
<newOrder>
<xsl:for-each select="noField">
<xsl:variable name="curPos" select="position()" />
<newOField>
<xsl:value-of select="/doc/order/oField[$curPos]/@name"/>
</newOField>
</xsl:for-each>
</newOrder>
</xsl:template>
输出为:
...
<newOrder>
<newOField>YEAR</newOField>
<newOField>MONTH</newOField>
<newOField>DAY</newOField>
</newOrder>
....
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="doc/noOrder">
<xsl:next-match/>
<newOrder>
<xsl:for-each select="noField">
<xsl:sort order="descending" select="@name"/>
<newOField><xsl:value-of select="@name"/></newOField>
</xsl:for-each>
</newOrder>
</xsl:template>
Try it.
XPath 中有一个 index-of
函数 https://www.w3.org/TR/xpath-functions/#func-index-of,我认为您可以使用它来根据其他属性值的顺序计算排序键:
<xsl:template match="doc/noOrder">
<xsl:next-match/>
<newOrder>
<xsl:variable name="sort-order" select="../order/oField/@name"/>
<xsl:for-each select="noField">
<xsl:sort select="index-of($sort-order, @name)"/>
<newOField>
<xsl:value-of select="@name"/>
</newOField>
</xsl:for-each>
</newOrder>
</xsl:template>
我有以下 XML 文档:
<?xml version="1.0" encoding="utf-8" ?>
<doc>
<order>
<oField name="YEAR"></oField>
<oField name="MONTH"></oField>
<oField name="DAY"></oField>
</order>
<noOrder>
<noField name="MONTH"></noField>
<noField name="YEAR"></noField>
<noField name="DAY"></noField>
</noOrder>
</doc>
我想做的是创建一个新元素,它是 order
和 noOrder
的同级元素,它基本上从 noField
元素中获取属性,但打印它们基于在上部 order
元素中的顺序。也许我很困惑,但这是我想要得到的结果 XML 文档:
<?xml version="1.0" encoding="UTF-8"?>
<doc>
<order>
<oField name="YEAR"/>
<oField name="MONTH"/>
<oField name="DAY"/>
</order>
<noOrder>
<noField name="MONTH"/>
<noField name="YEAR"/>
<noField name="DAY"/>
</noOrder>
<newOrder>
<newOField>YEAR</newOField>
<newOField>MONTH</newOField>
<newOField>DAY</newOField>
</newOrder>
</doc>
请注意 oField
和 noField
元素的属性 name
将相同,但我不想从 [=20= 获取数据] 元素,这些元素已经被订购。我想从noField
个元素中获取,
这是我目前拥有的 XSLT 代码:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0">
<xsl:output indent="yes" cdata-section-elements="xml-property"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="doc/noOrder">
<xsl:next-match/>
<newOrder>
<xsl:for-each select="noField">
<!--<xsl:sort select="/doc/order/oField[position()]"/>-->
<newOField>
<xsl:value-of select="@name"/>
</newOField>
</xsl:for-each>
</newOrder>
</xsl:template>
</xsl:stylesheet>
产生以下结果:
<?xml version="1.0" encoding="UTF-8"?>
<doc>
<order>
<oField name="YEAR"/>
<oField name="MONTH"/>
<oField name="DAY"/>
</order>
<noOrder>
<noField name="MONTH"/>
<noField name="YEAR"/>
<noField name="DAY"/>
</noOrder>
<newOrder>
<newOField>MONTH</newOField>
<newOField>YEAR</newOField>
<newOField>DAY</newOField>
</newOrder>
</doc>
正如您在我的 XSLT 代码的注释行中看到的那样,我尝试将 xsl:sort
元素设置为按 oField
元素排序,但由于其中有三个元素,/doc/order/oField[position()]
returns 多个值并且无法完成排序(这就是注释该行的原因)
简单的解决方案是通过 oField
元素设置 xsl:for-each
,但正如我之前所说,这不是我想要的,
XSLT 中有没有办法做到这一点?
谢谢!
EDIT/UPDATE
也许我写问题的方式有点混乱,但我想从元素中的属性中获取数据,而不是从元素中获取数据。但是因为它们是相同的(并且元素完全相同,具有相同的属性值),我想按照它们在元素中出现的顺序打印属性中的值(在元素中,在元素内部)
谢谢!
亚历山大·哈辛托
我不确定我是否正确理解了你的问题。
试试下面的模板,输出是你想要的。它使用 noField
的 position()
作为 oField
的索引并打印其 @name
属性。
<xsl:template match="doc/noOrder">
<xsl:next-match/>
<newOrder>
<xsl:for-each select="noField">
<xsl:variable name="curPos" select="position()" />
<newOField>
<xsl:value-of select="/doc/order/oField[$curPos]/@name"/>
</newOField>
</xsl:for-each>
</newOrder>
</xsl:template>
输出为:
...
<newOrder>
<newOField>YEAR</newOField>
<newOField>MONTH</newOField>
<newOField>DAY</newOField>
</newOrder>
....
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="doc/noOrder">
<xsl:next-match/>
<newOrder>
<xsl:for-each select="noField">
<xsl:sort order="descending" select="@name"/>
<newOField><xsl:value-of select="@name"/></newOField>
</xsl:for-each>
</newOrder>
</xsl:template>
Try it.
XPath 中有一个 index-of
函数 https://www.w3.org/TR/xpath-functions/#func-index-of,我认为您可以使用它来根据其他属性值的顺序计算排序键:
<xsl:template match="doc/noOrder">
<xsl:next-match/>
<newOrder>
<xsl:variable name="sort-order" select="../order/oField/@name"/>
<xsl:for-each select="noField">
<xsl:sort select="index-of($sort-order, @name)"/>
<newOField>
<xsl:value-of select="@name"/>
</newOField>
</xsl:for-each>
</newOrder>
</xsl:template>