XPath - 从字符串中提取数值

时间:2012-01-17 07:26:04

标签: xml xslt xpath stylesheet

<Description>this is my value 822880494 this is my value</Description>

我对xpath,xml和stylevision都很陌生,所以这可能是一个基本问题。

我正在使用stylevision 2010和xpath为架构创建sps / xslt。

在上面的节点中,您可以看到节点内部有一个数值,我想提取该值并将其转换为我的pdf / html中的链接。问题是我似乎无法提取它。子字符串不是一个选项,因为值的长度和其中数值的位置会有所不同。

有些人可能会认为模式组成严重,数值应该在一个单独的节点/属性中......由于这个模式是由另一家公司提供的,所以我无能为力。

提前致谢!

5 个答案:

答案 0 :(得分:14)

使用这个简单的XPath 1.0表达式

translate(.,translate(., '0123456789', ''), '')

这是一个完整的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:strip-space elements="*"/>

 <xsl:template match="/*">
     <xsl:value-of select=
      "translate(.,translate(., '0123456789', ''), '')"/>
 </xsl:template>
</xsl:stylesheet>

将此转换应用于提供的XML文档

<Description>this is my value 822880494 this is my value</Description>

产生了想要的正确结果:

822880494

<强>解释

这被称为Michael Kay首先提出的 Double Translate Method 。它包含两个对translate()函数的嵌套调用:

  1. 内部translate() 。这会生成字符串的所有字符,但数字除外。

  2. translate() 。这将从字符串中删除内部translate()生成的所有字符。剩下的只是想要的字符(数字)。

答案 1 :(得分:8)

StyleVision 2010似乎支持XSLT 2.0,因此您可以使用2.0样式表并执行类似

的操作
<xsl:analyze-string select='$foo' regex='\d+'>
  <xsl:matching-substring>
    <number><xsl:value-of select='.' /></number>
  </xsl:matching-substring>
</xsl:analyze-string>

或者你想用这个号码做什么;带有数字的字符串是<xsl:matching-substring>元素中的上下文元素。

Newtover的translate想法(对于XSLT 1.0)看起来像这样:

<xsl:value-of select="translate(., translate(., '0123456789', ''), '')" />

但如果您的输入包含多个数字,那么只需将它们连接起来。

答案 2 :(得分:2)

普通XSLT 1.0中一个脆弱但可能的解决方案是使用translate的组合(使所有非数字值为空字符串或空格)和normalize-space(以修剪剩下的空格,虽然translate可能就足够了)。只有在字符串中没有其他数值时,这肯定会起作用。而且,我目前无法检查,translate可能仅在您的字符串包含ascii字符时才有效。

XSLT 2.0有几个regexp功能。如果你的xslt处理器允许使用EXSLT扩展,它也包含regexp函数,或者你可以用空格标记你的字符串,并且只为数字标记提供非空模板。

P.S。对不起,我没有提供任何链接,很难从设备上获取。

答案 3 :(得分:2)

嗨,这将产生您需要的结果!它检查每个字符,然后确保它是一个数字。

XSLT 1解决方案

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
    >
        <xsl:output method="xml" indent="yes"/>

        <xsl:template match="Root/Description">
            <xsl:call-template name="for-each-character">
                <xsl:with-param name="data" select="."/>
            </xsl:call-template>
        </xsl:template>

        <xsl:template name="for-each-character">
            <xsl:param name="data"/>
            <xsl:if test="string-length($data) &gt; 0">
                <xsl:if test="substring($data,1,1)&gt;-1">
                    <xsl:value-of select="substring($data,1,1)"/>
                </xsl:if>
                <xsl:call-template name="for-each-character">
                    <xsl:with-param name="data" select="substring($data,2)"/>
                </xsl:call-template>
            </xsl:if>
        </xsl:template>
    </xsl:stylesheet>

答案 4 :(得分:0)

以下是上述XSLT v1解决方案的派生产品,但是,这是专门针对前导数字的,而不是嵌入在字符串的中间。它还允许进行浮点或整数解析。 (我个人认为这对于将单位与“ 80 mg”或“ 128.4 mm2”(其中单位为“ mm2”,值“ 128.4”,而不是“ 128.42”)分开是很有用的。

<xsl:template name="parseNumber">
<xsl:param name="data"/>
<xsl:param name="is-float" select="false()"/><!-- has this already been determined to be a non-integer -->
<xsl:if test="string-length($data) &gt; 0">
  <xsl:if test="(substring($data,1,1)&gt;-1) or ((substring($data,1,1) = '.') and (not($is-float)) )">
    <xsl:value-of select="substring($data,1,1)"/>
    <xsl:call-template name="parseNumber">
      <xsl:with-param name="data" select="substring($data,2)"/>
      <xsl:with-param name="is-float" select="(substring($data,1,1) = '.') or ($is-float)"/>
    </xsl:call-template>
  </xsl:if>
</xsl:if>
</xsl:template>

以下是一些具有比较结果的单元测试案例:

Test: [123] ?=? numer(): [123] ?=? for-each-char: [123] ?=? parseNumber: [123]
Test: [1.23] ?=? numer(): [1.23] ?=? for-each-char: [1.23] ?=? parseNumber: [1.23]
Test: [1.1.1.1] ?=? numer(): [NaN] ?=? for-each-char: [1.1.1.1] ?=? parseNumber: [1.1]
Test: [123 abc] ?=? numer(): [NaN] ?=? for-each-char: [123] ?=? parseNumber: [123]
Test: [123 abc2] ?=? numer(): [NaN] ?=? for-each-char: [1232] ?=? parseNumber: [123]
Test: [123.456 abc7] ?=? numer(): [NaN] ?=? for-each-char: [123.4567] ?=? parseNumber: [123.456]
Test: [abc def ] ?=? numer(): [NaN] ?=? for-each-char: [] ?=? parseNumber: []
Test: [abc 123] ?=? numer(): [NaN] ?=? for-each-char: [123] ?=? parseNumber: []