【问题标题】:XPath - extract numeric value out of stringXPath - 从字符串中提取数值
【发布时间】:2012-02-12 01:02:29
【问题描述】:
<Description>this is my value 822880494 this is my value</Description>

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

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

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

有些人可能会认为架构的组合很糟糕,并且数值应该在单独的节点/属性/中...我对此无能为力,因为此架构是由另一家公司提供的。

提前致谢!

【问题讨论】:

    标签: xml xslt xpath stylesheet


    【解决方案1】:

    使用这个简单的 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 首次提出。它由对translate() 函数的两个嵌套调用组成:

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

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

    【讨论】:

      【解决方案2】:

      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>
      

      或者你想对这个号码做什么;带有数字的字符串是&lt;xsl:matching-substring&gt; 元素内的上下文元素。

      Newtover 的 translate 想法(适用于 XSLT 1.0)如下所示:

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

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

      【讨论】:

      • 巧妙地使用了翻译 :)
      • 我喜欢翻译解决方案,确实非常聪明。但是节点内部可能还有其他一些松散的数字,所以我选择了类似于您建议的 2.0 的正则表达式解决方案。谢谢。
      【解决方案3】:

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

      XSLT 2.0 有几个正则表达式函数。如果您的 xslt 处理器允许使用 EXSLT 扩展,它还包含正则表达式函数,或者您可以通过空格标记您的字符串并仅向数字标记提供非空模板。

      附言很抱歉,我没有提供任何链接,很难从设备中获取。

      【讨论】:

        【解决方案4】:

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

        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>
        

        【讨论】:

        • msxsl 是干什么用的?另外,请参阅我的答案,了解使用 XPath 函数的稍短版本。
        • 刚刚从文档中复制它可以删除 ofc :) 无论如何添加到 vs2008 从来没有造成任何问题,答案也是像我这样被 xslt 1.0 卡住的偷窥者
        【解决方案5】:

        以下是上述 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: []
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-10-06
          • 1970-01-01
          • 2021-04-14
          • 1970-01-01
          • 2020-07-25
          • 2023-02-07
          相关资源
          最近更新 更多