如何使用XPath 1.0比较字符串?(How to compare strings with Xp

2019-06-25 15:34发布

我experiiencing与问题< XPath 1.0中的字符串操作。

这个简单的XPath表达式

'A' < 'B' (or the equivalent 'A' &lt; 'B')

没有评估为真,在我的libxslt XSLT运行(这是一个XSLT 1.0引擎)。

我在XML间谍,这使得在1.0和2.0,果然测试的XPath表达式检查,XPath 2.0中它的计算结果为true ,但在XPath 1.0计算结果为false

这是XPath 1.0中的错误吗?

我应该使用什么其他的表达两个字符串/字符比较他们的字母顺序? 请注意,compare()函数不会做,因为这是一个XSLT 2.0功能。

Answer 1:

是的,这是XPath 1.0中的限制。 (我不认为这是合理的,指的是你不喜欢的“错误”的限制,但明确的XPath 2.0的设计人员同意你的观点,这是一个不受欢迎的限制)。

您已经标记问题“XSLT”,所以你可能能够解决此问题在XSLT水平,至少如果您的处理器具有节点集扩展:

<xsl:variable name="nodes">
  <node><xsl:value-of select="$A"/></node>
  <node><xsl:value-of select="$B"/></node>
</xsl:variable>

<xsl:for-each select="exslt:node-set($nodes)/*">
  <xsl:sort select="."/>
  <xsl:if test="position()=1 and .=$A">A comes first!</xsl:if>
</xsl:for-each>

但也许是时候转移到2.0。 什么阻碍了你?



Answer 2:

在XPath 1.0,字符串比较只对定义=!= ,和排序比较不可用。 细则中指出

当要比较既不对象是一个节点集合和操作者<=,<,> =或>,则目的是通过根据IEEE 754两个对象转换到数字和比较所述数字比较。

因此,这两个操作数的被转换为浮动,使他们既为NaN。

我相信微软的XML增加扩展功能来处理这个问题,但当然这有助于仅当您正在使用MSXML。



Answer 3:

在希望,这被证明是有用的人太多,下面是我写了下面的迈克尔·凯的建议代码。 我写了一个自定义的compare函数,提供相同的结果XPath 2.0中的一个。 我还添加了php标签,这样它会更经常发现的问题。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
    version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:func="http://exslt.org/functions"
    xmlns:common="http://exslt.org/common"
    xmlns:custom="urn:myCustomFunctions"
    exclude-result-prefixes="func common custom" 
    extension-element-prefixes="func custom">

    <xsl:output method="xml"/>

    <func:function name="custom:compare">
        <xsl:param name="string1"/>
        <xsl:param name="string2"/>

        <func:result>
            <xsl:choose>
                <xsl:when test="$string1 = $string2">0</xsl:when>
                <xsl:otherwise>
                    <xsl:variable name="nodes">
                        <node><xsl:value-of select="$string1"/></node>
                        <node><xsl:value-of select="$string2"/></node>
                    </xsl:variable>
                    <xsl:for-each select="common:node-set($nodes)/*">
                        <xsl:sort select="."/>
                        <xsl:choose>
                            <xsl:when test="position()=1 and .=$string1">-1</xsl:when>
                            <xsl:when test="position()=1 and .=$string2">1</xsl:when>
                        </xsl:choose>
                    </xsl:for-each>
                </xsl:otherwise>
            </xsl:choose>
        </func:result>
    </func:function>

    <xsl:template match="/">
        <out>
            <test1><xsl:value-of select="custom:compare('A', 'B')"/></test1>
            <test2><xsl:value-of select="custom:compare('A', 'A')"/></test2>
            <test3><xsl:value-of select="custom:compare('C', 'B')"/></test3>
            <test4><xsl:value-of select="custom:compare('DD', 'A')"/></test4>
        </out>
    </xsl:template>

</xsl:stylesheet>

运行这样(伪输入)的结果是

<?xml version="1.0"?>
<out>
    <test1>-1</test1>
    <test2>0</test2>
    <test3>1</test3>
    <test4>1</test4>
</out>

对于那些谁希望在PHP中为自己进行测试,下面是我使用的代码:

<?php 
$xslt = new XSLTProcessor();
$xslt->importStylesheet( DOMDocument::load('testCompare.xslt') );
$xslt -> registerPHPFunctions();
$xml = new SimpleXMLElement('<test/>'); 
print $xslt->transformToXML( $xml );
?>


Answer 4:

这可能是丑陋的解决方案,并且在很多情况下并不可行,但对于简单的字母顺序比较,你可以使用translate 。 以下代码段只是可furtherly被扩展的一个示例:

  translate('A','ABCD','1234') &lt; translate('B','ABCD','1234');

您的翻译表达应涵盖所有的信件,并低的情况下,并且可以通过定义命名模板可以方便地重复使用。



文章来源: How to compare strings with Xpath 1.0?