XSLT:如何在不按内容排序的情况下反转输出

发布于 2024-08-25 10:09:37 字数 285 浏览 8 评论 0原文

我有一个项目列表:

<item>a</item>
<item>x</item>
<item>c</item>
<item>z</item>

我想要作为输出,

z
c
x
a

文件中没有订单信息,我只想反转这些行。源文件中的最后一行应该是输出中的第一行。如何使用 XSLT 解决此问题,而不按项目内容排序,这会给出错误的结果?

I have a list of items:

<item>a</item>
<item>x</item>
<item>c</item>
<item>z</item>

and I want as output

z
c
x
a

I have no order information in the file and I just want to reverse the lines. The last line in the source file should be first line in the output. How can I solve this problem with XSLT without sorting by the content of the items, which would give the wrong result?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

一绘本一梦想 2024-09-01 10:09:37

我将展示两个 XSLT 解决方案

I.具有递归功能的 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:template match="/*">
     <xsl:call-template name="reverse">
       <xsl:with-param name="pList" select="*"/>
     </xsl:call-template>
    </xsl:template>

    <xsl:template name="reverse">
      <xsl:param name="pList"/>

      <xsl:if test="$pList">
        <xsl:value-of
         select="concat($pList[last()], '
')"/>

        <xsl:call-template name="reverse">
          <xsl:with-param name="pList"
            select="$pList[not(position() = last())]"/>
        </xsl:call-template>
      </xsl:if>
    </xsl:template>
</xsl:stylesheet>

当应用于此 XML 文档时

<t>
    <item>a</item>
    <item>x</item>
    <item>c</item>
    <item>z</item>
</t>

产生想要的结果

z
c
x
a

II。 XSLT 2.0 解决方案

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output method="text"/>

  <xsl:template match="/*">
   <xsl:value-of select="reverse(*)/string(.)"
    separator="
"/>
  </xsl:template>
</xsl:stylesheet>

当此转换应用于同一个 XML 文档时,会产生相同的正确结果。

I will present two XSLT solutions:

I. XSLT 1.0 with recursion Note that this solution works for any node-set, not only in the case when the nodes are siblings:

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:template match="/*">
     <xsl:call-template name="reverse">
       <xsl:with-param name="pList" select="*"/>
     </xsl:call-template>
    </xsl:template>

    <xsl:template name="reverse">
      <xsl:param name="pList"/>

      <xsl:if test="$pList">
        <xsl:value-of
         select="concat($pList[last()], '
')"/>

        <xsl:call-template name="reverse">
          <xsl:with-param name="pList"
            select="$pList[not(position() = last())]"/>
        </xsl:call-template>
      </xsl:if>
    </xsl:template>
</xsl:stylesheet>

when applied on this XML document:

<t>
    <item>a</item>
    <item>x</item>
    <item>c</item>
    <item>z</item>
</t>

produces the wanted result:

z
c
x
a

II. XSLT 2.0 solution :

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xsl:output method="text"/>

  <xsl:template match="/*">
   <xsl:value-of select="reverse(*)/string(.)"
    separator="
"/>
  </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the same XML document, the same correct result is produced.

涫野音 2024-09-01 10:09:37

XML 代码:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<device>
<element>a</element>
<element>x</element>
<element>c</element>
<element>z</element>
</device>

XSLT 代码:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="//device">
<xsl:for-each select="element">

<xsl:sort select="position()" data-type="number" order="descending"/>

<xsl:text> </xsl:text>
<xsl:value-of select="."/>
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>

注意: 如果您使用的是 data-type="number",并且任何值都不是数字,那些非数字值将排序在数字值之前。这意味着如果您使用 order="ascending",则非数字值首先出现;如果使用 order="descending",则非数字值显示在最后。

注意非数字值没有排序;它们只是按照遇到的顺序出现在输出文档中。

另外,您可能会发现阅读以下内容很有用:

http://docstore.mik.ua/orelly/xml/xslt /ch06_01.htm

XML CODE:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<device>
<element>a</element>
<element>x</element>
<element>c</element>
<element>z</element>
</device>

XSLT CODE:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="//device">
<xsl:for-each select="element">

<xsl:sort select="position()" data-type="number" order="descending"/>

<xsl:text> </xsl:text>
<xsl:value-of select="."/>
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>

note: if you're using data-type="number", and any of the values aren't numbers, those non-numeric values will sort before the numeric values. That means if you're using order="ascending", the non-numeric values appear first; if you use order="descending", the non-numeric values appear last.

Notice that the non-numeric values were not sorted; they simply appear in the output document in the order in which they were encountered.

also, you may find usefull to read this:

http://docstore.mik.ua/orelly/xml/xslt/ch06_01.htm

冷清清 2024-09-01 10:09:37

不确定完整的 XML 是什么样子,因此我将其封装在 元素中以使其格式良好:

<doc>
<item>a</item>
<item>x</item>
<item>c</item>
<item>z</item>
</doc>

针对此样式表运行示例 XML:

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

    <xsl:template match="/">
        <xsl:call-template name="reverse">
            <xsl:with-param name="item" select="doc/item[position()=last()]" />
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="reverse">
        <xsl:param name="item" />

        <xsl:value-of select="$item" />
        <!--Adds a line feed-->
        <xsl:text>
</xsl:text>

        <!--Move on to the next item, if we aren't at the first-->
        <xsl:if test="$item/preceding-sibling::item">
            <xsl:call-template name="reverse">
                <xsl:with-param name="item" select="$item/preceding-sibling::item[1]" />
            </xsl:call-template>
        </xsl:if>

    </xsl:template>

</xsl:stylesheet>

生成请求的输出:

z
c
x
a

您可能需要调整xpath 与您的实际 XML 相匹配。

Not sure what the full XML looks like, so I wrapped in a <doc> element to make it well formed:

<doc>
<item>a</item>
<item>x</item>
<item>c</item>
<item>z</item>
</doc>

Running that example XML against this stylesheet:

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

    <xsl:template match="/">
        <xsl:call-template name="reverse">
            <xsl:with-param name="item" select="doc/item[position()=last()]" />
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="reverse">
        <xsl:param name="item" />

        <xsl:value-of select="$item" />
        <!--Adds a line feed-->
        <xsl:text>
</xsl:text>

        <!--Move on to the next item, if we aren't at the first-->
        <xsl:if test="$item/preceding-sibling::item">
            <xsl:call-template name="reverse">
                <xsl:with-param name="item" select="$item/preceding-sibling::item[1]" />
            </xsl:call-template>
        </xsl:if>

    </xsl:template>

</xsl:stylesheet>

Produces the requested output:

z
c
x
a

You may need to adjust the xpath to match your actual XML.

清风疏影 2024-09-01 10:09:37

考虑这个 XML 输入:

<?xml version="1.0" encoding="utf-8" ?>
<items>
  <item>a</item>
  <item>x</item>
  <item>c</item>
  <item>z</item>
</items>

XSLT:

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

    <xsl:output method="text" />

    <xsl:template match="/items[1]">

      <xsl:variable name="items-list" select="." />
      <xsl:variable name="items-count" select="count($items-list/*)" />

      <xsl:for-each select="item">
        <xsl:variable name="index" select="$items-count+1  - position()"/>
        <xsl:value-of select="$items-list/item[$index]"/>
        <xsl:value-of select="'
'"/>
      </xsl:for-each>

    </xsl:template>
</xsl:stylesheet>

以及结果:

z
c
x
a

Consider this XML input:

<?xml version="1.0" encoding="utf-8" ?>
<items>
  <item>a</item>
  <item>x</item>
  <item>c</item>
  <item>z</item>
</items>

The XSLT:

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

    <xsl:output method="text" />

    <xsl:template match="/items[1]">

      <xsl:variable name="items-list" select="." />
      <xsl:variable name="items-count" select="count($items-list/*)" />

      <xsl:for-each select="item">
        <xsl:variable name="index" select="$items-count+1  - position()"/>
        <xsl:value-of select="$items-list/item[$index]"/>
        <xsl:value-of select="'
'"/>
      </xsl:for-each>

    </xsl:template>
</xsl:stylesheet>

And the result:

z
c
x
a
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文