我是xslt转换的新手,我遇到了一些麻烦。 我需要对元素进行排序和过滤,在下面的示例中,我设法使用两个xlt转换对输入xml进行排序和过滤。 我的问题是:如何使用单个xsl文件对排序数据进行排序和过滤? 提前谢谢。
XML输入:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<data>
<id>00000_1111_2222</id>
<startedAt>2017-08-21T11:55:08.382Z</startedAt>
<endedAt>2017-08-21T12:07:08.539Z</endedAt>
<positions>
<timestamp>2017-08-21T11:55:28.041Z</timestamp>
<latitude>40.2407009</latitude>
<longitude>10.7750499</longitude>
</positions>
<positions>
<timestamp>2017-08-21T11:55:28.041Z</timestamp>
<latitude>40.2409364</latitude>
<longitude>10.7748426</longitude>
</positions>
<positions>
<timestamp>2017-08-21T11:55:38.041Z</timestamp>
<latitude>40.240409</latitude>
<longitude>10.7751432</longitude>
</positions>
</data>
</root>
&#13;
XSL排序:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs" version="2.0">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="data">
<xsl:copy>
<xsl:apply-templates select="*[not(self::positions)]"/>
<xsl:apply-templates select="positions">
<xsl:sort select="timestamp" order="descending"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
&#13;
XSL过滤:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="data">
<xsl:copy>
<xsl:apply-templates select="*[not(self::positions)]" />
<xsl:copy-of select="positions[position() <= 4]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
&#13;
如果我保留原始xmlstructure,它是否与此xsl相关?
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="1.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:output omit-xml-declaration="no" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- Identity template -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- Sort and filter positions elements -->
<xsl:template match="data">
<xsl:copy>
<xsl:for-each select="positions">
<xsl:sort select="timestamp" order="descending"/>
<xsl:if test="position() <= 2">
<xsl:apply-templates select="."/>
</xsl:if>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
&#13;
我的预期输出XML将是:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<data>
<id>00000_1111_2222</id>
<startedAt>2017-08-21T11:55:08.382Z</startedAt>
<endedAt>2017-08-21T12:07:08.539Z</endedAt>
<positions>
<timestamp>2017-08-21T11:55:38.041Z</timestamp>
<latitude>40.240409</latitude>
<longitude>10.7751432</longitude>
</positions>
<positions>
<timestamp>2017-08-21T11:55:28.041Z</timestamp>
<latitude>40.2407009</latitude>
<longitude>10.7750499</longitude>
</positions>
</data>
</root>
&#13;
但是通过这种方式,我放弃了所有元素,而不是&#34;位置&#34;元素:id,startedAt,endsAt。
所以我试着添加:<xsl:apply-templates select="*
[not(self :: positions)]&#34; /&gt;在<xsl:template match="data">
之后它可以工作,但是如果所有不是&#34;位置&#34;孩子们,是位置元素之后?这样我将松开原始的xml结构/顺序。有没有办法以通用的方式实现这最后的事情?
谢谢。
答案 0 :(得分:1)
鉴于XSLT 2.0,您可以使用
<xsl:variable name="sorted-positions" as="element(positions)*">
<xsl:perform-sort select="positions">
<xsl:sort select="timestamp" order="descending"/>
</xsl:perform-sort>
</xsl:variable>
然后<xsl:copy-of select="$sorted-positions[position() le 4]"/>
(或者当然是这些元素的应用模板)。
或者您可以使用例如
<xsl:apply-templates select="positions">
<xsl:sort select="timestamp" order="descending"/>
</xsl:apply-templates>
然后
<xsl:template match="positions">
<xsl:if test="position() le 4">
<xsl:next-match/>
</xsl:if>
</xsl:template>
使用XSLT 1.0,您当然可以使用例如。
<xsl:for-each select="positions">
<xsl:sort select="timestamp" order="descending"/>
<xsl:if test="position() <= 4">
<xsl:apply-templates select="."/>
</xsl:if>
</xsl:for-each>
当然也可以选择使用copy-of
代替apply-templates
。
最后,使用XSLT 3.0并支持sort
函数(https://www.w3.org/TR/xpath-functions-31/#func-sort),您可以直接apply-templates
查看已排序的序列(或者在您的情况下,reverse
d排序序列以降序排序)和过滤后的序列:
<xsl:template match="data">
<xsl:copy>
<xsl:apply-templates select="* except positions, reverse(sort(positions, (), function($p) { $p/timestamp}))[position() le 4]"/>
</xsl:copy>
</xsl:template>