当我使用xsl:sort。
时,输出xml没有按预期排序正如您在结果部分中看到的,1.1.1.10,2.10,2.11,2.12未正确排序。
我希望排序列表如预期结果xml所示。
我在这里做错了吗?请帮忙。
输入XML
<children>
<child name="1.1.1.1 BDR Enter Customer" prefix="1.1.1.1"/>
<child name="1.1.1.10 BDR for Tax Office" prefix="1.1.1.10"/>
<child name="1.1.1.2 BDR Enter Customs" prefix="1.1.1.2"/>
<child name="1.1.1.3 BDR Enter Employee" prefix="1.1.1.3"/>
<child name="1.1.1.4 BDR Enter Forwarder" prefix="1.1.1.4"/>
<child name="1.1.1.5 BDR Enter Manufacturer" prefix="1.1.1.5"/>
<child name="1.1.1.6 BDR Enter Owner" prefix="1.1.1.6"/>
<child name="1.1.1.7 BDR Enter Person" prefix="1.1.1.7"/>
<child name="1.1.1.8 BDR Enter Resource" prefix="1.1.1.8"/>
<child name="1.1.1.9 BDR Enter Supplier" prefix="1.1.1.9"/>
<child name="1.1 Define System Basics" prefix="1.1"/>
<child name="2.9 Set Up Basic Data Accounting Rules" prefix="2.9"/>
<child name="2.2 Budget Management" prefix="2.2"/>
<child name="2.10 Customer Bill of Exchange Payment" prefix="2.10"/>
<child name="2.5 Depreciation Plan" prefix="2.5"/>
<child name="2.12 Supplier Credit Invoice" prefix="2.12"/>
<child name="2.11 AP/AR Nettings" prefix="2.11"/>
<child name="2.3 Arrival Entry Supplier Invoice" prefix="2.3"/>
<child name="2.1 Archive Data, Internal Ledger" prefix="2.1"/>
</children>
我的XSL
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="children">
<children>
<xsl:for-each select="child">
<xsl:sort select="@prefix"/>
<child>
<xsl:attribute name="name">
<xsl:value-of select="@name"/>
</xsl:attribute>
<xsl:attribute name="prefix">
<xsl:value-of select="@prefix"/>
</xsl:attribute>
</child>
</xsl:for-each>
</children>
</xsl:template>
</xsl:stylesheet>
结果
<?xml version="1.0" encoding="utf-8"?>
<children>
<child name="1.1 Define System Basics" prefix="1.1"/>
<child name="1.1.1.1 BDR Enter Customer" prefix="1.1.1.1"/>
<child name="1.1.1.10 BDR for Tax Office" prefix="1.1.1.10"/>
<child name="1.1.1.2 BDR Enter Customs" prefix="1.1.1.2"/>
<child name="1.1.1.3 BDR Enter Employee" prefix="1.1.1.3"/>
<child name="1.1.1.4 BDR Enter Forwarder" prefix="1.1.1.4"/>
<child name="1.1.1.5 BDR Enter Manufacturer" prefix="1.1.1.5"/>
<child name="1.1.1.6 BDR Enter Owner" prefix="1.1.1.6"/>
<child name="1.1.1.7 BDR Enter Person" prefix="1.1.1.7"/>
<child name="1.1.1.8 BDR Enter Resource" prefix="1.1.1.8"/>
<child name="1.1.1.9 BDR Enter Supplier" prefix="1.1.1.9"/>
<child name="2.1 Archive Data, Internal Ledger" prefix="2.1"/>
<child name="2.10 Customer Bill of Exchange Payment" prefix="2.10"/>
<child name="2.11 AP/AR Nettings" prefix="2.11"/>
<child name="2.12 Supplier Credit Invoice" prefix="2.12"/>
<child name="2.2 Budget Management" prefix="2.2"/>
<child name="2.3 Arrival Entry Supplier Invoice" prefix="2.3"/>
<child name="2.5 Depreciation Plan" prefix="2.5"/>
<child name="2.9 Set Up Basic Data Accounting Rules" prefix="2.9"/>
</children>
预期结果
<?xml version="1.0" encoding="utf-8"?>
<children>
<child name="1.1 Define System Basics" prefix="1.1"/>
<child name="1.1.1.1 BDR Enter Customer" prefix="1.1.1.1"/>
<child name="1.1.1.2 BDR Enter Customs" prefix="1.1.1.2"/>
<child name="1.1.1.3 BDR Enter Employee" prefix="1.1.1.3"/>
<child name="1.1.1.4 BDR Enter Forwarder" prefix="1.1.1.4"/>
<child name="1.1.1.5 BDR Enter Manufacturer" prefix="1.1.1.5"/>
<child name="1.1.1.6 BDR Enter Owner" prefix="1.1.1.6"/>
<child name="1.1.1.7 BDR Enter Person" prefix="1.1.1.7"/>
<child name="1.1.1.8 BDR Enter Resource" prefix="1.1.1.8"/>
<child name="1.1.1.9 BDR Enter Supplier" prefix="1.1.1.9"/>
<child name="1.1.1.10 BDR for Tax Office" prefix="1.1.1.10"/>
<child name="2.1 Archive Data, Internal Ledger" prefix="2.1"/>
<child name="2.2 Budget Management" prefix="2.2"/>
<child name="2.3 Arrival Entry Supplier Invoice" prefix="2.3"/>
<child name="2.5 Depreciation Plan" prefix="2.5"/>
<child name="2.9 Set Up Basic Data Accounting Rules" prefix="2.9"/>
<child name="2.10 Customer Bill of Exchange Payment" prefix="2.10"/>
<child name="2.11 AP/AR Nettings" prefix="2.11"/>
<child name="2.12 Supplier Credit Invoice" prefix="2.12"/>
</children>
答案 0 :(得分:1)
使用XSLT 3.0和XPath 3.1中的sort
函数,您可以使用
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output indent="yes"/>
<xsl:template match="children">
<xsl:copy>
<xsl:apply-templates select="sort(child, (), function($c) { tokenize($c/@prefix, '\.')!xs:integer(.) })"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Saxon 9.7 PE或EE以及最新版本的Altova XMLSpy或Raptor支持XSLT 3.0。
使用Saxon 9(包括HE),您可以使用collation="http://saxon.sf.net/collation?alphanumeric=yes"
上的XSLT 2.0和xsl:sort
来执行此操作:
<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 indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="children">
<xsl:copy>
<xsl:apply-templates select="child">
<xsl:sort select="@prefix" collation="http://saxon.sf.net/collation?alphanumeric=yes"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:1)
我在这里做错了吗?
是的,你做错了两件事:
首先,您使用单个排序键进行排序,而实际上您有四个排序键(至少) - @prefix
的单独段由'。'分隔字符。
在第二位,您似乎希望每个键按数字排序,但您接受默认的词典排序。
在XSLT中,您可以通过提供多个xsl:sort
元素按多个键排序,并且可以通过这些元素的data-type
属性进行数字排序。但是,如果您被限制为没有扩展名的XSLT 1.0,那么这仍然会让您在将前缀属性分解为键时遇到一些棘手的问题。对于固定的最大段数,您可以这样做:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="children">
<xsl:copy>
<xsl:apply-templates select="child">
<xsl:sort data-type="number"
select="substring-before(@prefix, '.')"/>
<xsl:sort data-type="number"
select="substring-before(substring-after(concat(@prefix, '.0.0.0.'), '.'), '.')"/>
<xsl:sort data-type="number"
select="substring-before(substring-after(substring-after(concat(@prefix, '.0.0.0.'), '.'), '.'), '.')"/>
<xsl:sort data-type="number"
select="substring-before(substring-after(substring-after(substring-after(concat(@prefix, '.0.0.0.'), '.'), '.'), '.'), '.')"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
请注意使用substring-before()
和substring-after()
函数来挑选“。”前缀。分隔符,以及'.0.0.0.'
与前缀的串联,以确保所有前缀都被视为相同,无论深度如何,直到最大支持深度(在这种情况下为四,但可以扩展到任何深度都需要) )。
另请注意,xsl:copy
通常优先于文字输出元素xsl:element
或xsl:attribute
,前者适用,并且排序可应用于{{1 }},也不仅仅是xsl:apply-templates
。
答案 2 :(得分:0)
如果没有办法通过向前推进到更新的XSLT版本或利用供应商扩展来实现这一点,那么我将解决它的方法是预处理XML修改内容
v <- " John Andrew Thomas"
paste0(stringi::stri_extract_all_words(v, simplify = TRUE), "@gmail.com", collapse = ";")
到
#[1] "John@gmail.com;Andrew@gmail.com;Thomas@gmail.com"
然后使用多部分排序键进行排序:
<child name="1.1.1.10 BDR for Tax Office" prefix="1.1.1.10"/>
预处理可以使用一系列指令完成,例如
<child name="1.1.1.10 BDR for Tax Office" prefix="1.1.1.10"
k1="1" k2="1" k3="1" k4="10"/>