使用 XSL 1.0 的自定义排序问题
Custom sort issue using XSL 1.0
我正在尝试根据自定义排序要求对 XML 中的元素进行排序。首先,我需要根据 VerificationCode 中的第一个字符按 V、P、U、A、C、R 的顺序进行排序。然后我需要根据第二个和第三个字符中的数字进行排序。
我使用的样本xml是
<ns3:Response xmlns:ns3="http://www.example.org">
<ns3:Codes>
<ns3:Name>US</ns3:Name>
<ns3:VerificationCode>A42</ns3:VerificationCode>
</ns3:Codes>
<ns3:Codes>
<ns3:Name>CH</ns3:Name>
<ns3:VerificationCode>V54</ns3:VerificationCode>
</ns3:Codes>
<ns3:Codes>
<ns3:Name>IN</ns3:Name>
<ns3:VerificationCode>U14</ns3:VerificationCode>
</ns3:Codes>
<ns3:Codes>
<ns3:Name>MY</ns3:Name>
<ns3:VerificationCode>V84</ns3:VerificationCode>
</ns3:Codes>
<ns3:Codes>
<ns3:Name>MX</ns3:Name>
<ns3:VerificationCode>C34</ns3:VerificationCode>
</ns3:Codes>
</ns3:Response>
我拥有的第一级 XSL 如下所示。但它什么也没做。
<xsl:stylesheet version="1.0" xmlns:ns0="http://www.example.org" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="*">
<xsl:variable name="sortOrder1" select="'|V|P|U|A|C|R'" />
<xsl:apply-templates select="ns0:Codes">
<xsl:sort select="string-length(substring-before($sortOrder1, concat('|', substring(ns0:VerificationCode,1,1), '|')))" data-type="number"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="/">
<ns0:Response>
<xsl:copy-of select="/ns0:Response"/>
</ns0:Response>
</xsl:template>
</xsl:stylesheet>
下面是预期的输出
<ns3:Response xmlns:ns3="http://www.example.org">
<ns3:Codes>
<ns3:Name>MY</ns3:Name>
<ns3:VerificationCode>V84</ns3:VerificationCode>
</ns3:Codes>
<ns3:Codes>
<ns3:Name>CH</ns3:Name>
<ns3:VerificationCode>V54</ns3:VerificationCode>
</ns3:Codes>
<ns3:Codes>
<ns3:Name>IN</ns3:Name>
<ns3:VerificationCode>U14</ns3:VerificationCode>
</ns3:Codes>
<ns3:Codes>
<ns3:Name>US</ns3:Name>
<ns3:VerificationCode>A42</ns3:VerificationCode>
</ns3:Codes>
<ns3:Codes>
<ns3:Name>MX</ns3:Name>
<ns3:VerificationCode>C34</ns3:VerificationCode>
</ns3:Codes>
</ns3:Response>
如果要应用模板,则不能在根节点上使用 copy-of
,也可以简单地匹配特定的 Response
元素:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://www.example.org"
version="1.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ns0:Response">
<xsl:copy>
<xsl:variable name="sortOrder1" select="'|V|P|U|A|C|R'" />
<xsl:apply-templates select="ns0:Codes">
<xsl:sort select="string-length(substring-before($sortOrder1, concat('|', substring(ns0:VerificationCode,1,1), '|')))" data-type="number"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
但是,https://xsltfiddle.liberty-development.net/6rewNxR 的顺序与您显示的顺序略有不同,因为输入中的 V54 值在 V84 之前。
我花了一段时间才弄清楚你想要什么。您可以使用多个排序语句让您的生活更轻松,只有一个模板和 none 这些命名空间。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/Response">
<xsl:variable name="sortOrder" select="'VPUACR'" />
<Response>
<xsl:for-each select="Codes">
<xsl:sort select="string-length(substring-before($sortOrder, substring(VerificationCode/text(), 1, 1)))"/>
<xsl:sort select="substring(VerificationCode/text(), 1)" data-type="number"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</Response>
</xsl:template>
</xsl:stylesheet>
我正在尝试根据自定义排序要求对 XML 中的元素进行排序。首先,我需要根据 VerificationCode 中的第一个字符按 V、P、U、A、C、R 的顺序进行排序。然后我需要根据第二个和第三个字符中的数字进行排序。
我使用的样本xml是
<ns3:Response xmlns:ns3="http://www.example.org">
<ns3:Codes>
<ns3:Name>US</ns3:Name>
<ns3:VerificationCode>A42</ns3:VerificationCode>
</ns3:Codes>
<ns3:Codes>
<ns3:Name>CH</ns3:Name>
<ns3:VerificationCode>V54</ns3:VerificationCode>
</ns3:Codes>
<ns3:Codes>
<ns3:Name>IN</ns3:Name>
<ns3:VerificationCode>U14</ns3:VerificationCode>
</ns3:Codes>
<ns3:Codes>
<ns3:Name>MY</ns3:Name>
<ns3:VerificationCode>V84</ns3:VerificationCode>
</ns3:Codes>
<ns3:Codes>
<ns3:Name>MX</ns3:Name>
<ns3:VerificationCode>C34</ns3:VerificationCode>
</ns3:Codes>
</ns3:Response>
我拥有的第一级 XSL 如下所示。但它什么也没做。
<xsl:stylesheet version="1.0" xmlns:ns0="http://www.example.org" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="*">
<xsl:variable name="sortOrder1" select="'|V|P|U|A|C|R'" />
<xsl:apply-templates select="ns0:Codes">
<xsl:sort select="string-length(substring-before($sortOrder1, concat('|', substring(ns0:VerificationCode,1,1), '|')))" data-type="number"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="/">
<ns0:Response>
<xsl:copy-of select="/ns0:Response"/>
</ns0:Response>
</xsl:template>
</xsl:stylesheet>
下面是预期的输出
<ns3:Response xmlns:ns3="http://www.example.org">
<ns3:Codes>
<ns3:Name>MY</ns3:Name>
<ns3:VerificationCode>V84</ns3:VerificationCode>
</ns3:Codes>
<ns3:Codes>
<ns3:Name>CH</ns3:Name>
<ns3:VerificationCode>V54</ns3:VerificationCode>
</ns3:Codes>
<ns3:Codes>
<ns3:Name>IN</ns3:Name>
<ns3:VerificationCode>U14</ns3:VerificationCode>
</ns3:Codes>
<ns3:Codes>
<ns3:Name>US</ns3:Name>
<ns3:VerificationCode>A42</ns3:VerificationCode>
</ns3:Codes>
<ns3:Codes>
<ns3:Name>MX</ns3:Name>
<ns3:VerificationCode>C34</ns3:VerificationCode>
</ns3:Codes>
</ns3:Response>
如果要应用模板,则不能在根节点上使用 copy-of
,也可以简单地匹配特定的 Response
元素:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://www.example.org"
version="1.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ns0:Response">
<xsl:copy>
<xsl:variable name="sortOrder1" select="'|V|P|U|A|C|R'" />
<xsl:apply-templates select="ns0:Codes">
<xsl:sort select="string-length(substring-before($sortOrder1, concat('|', substring(ns0:VerificationCode,1,1), '|')))" data-type="number"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
但是,https://xsltfiddle.liberty-development.net/6rewNxR 的顺序与您显示的顺序略有不同,因为输入中的 V54 值在 V84 之前。
我花了一段时间才弄清楚你想要什么。您可以使用多个排序语句让您的生活更轻松,只有一个模板和 none 这些命名空间。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/Response">
<xsl:variable name="sortOrder" select="'VPUACR'" />
<Response>
<xsl:for-each select="Codes">
<xsl:sort select="string-length(substring-before($sortOrder, substring(VerificationCode/text(), 1, 1)))"/>
<xsl:sort select="substring(VerificationCode/text(), 1)" data-type="number"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</Response>
</xsl:template>
</xsl:stylesheet>