XPath - извлечь числовое значение из строки - PullRequest
3 голосов
/ 17 января 2012
<Description>this is my value 822880494 this is my value</Description>

Я довольно новичок в xpath, xml и stylevision, поэтому это может быть основной проблемой.

Я использую stylevision 2010 и xpath для создания sps / xslt для схемы.

В приведенном выше узле вы можете видеть, что внутри узла есть числовое значение, и я хочу извлечь это значение и превратить его в ссылку в моем pdf / html.Проблема в том, что я не могу извлечь его.Подстрока не является опцией, так как длина значения и положение числового значения внутри него различаются.

Некоторые, вероятно, подумают, что схема неправильно составлена ​​и что числовое значение должно находиться в отдельном узле /Атрибут / ... Я ничего не могу с этим поделать, так как эта схема предоставлена ​​другой компанией.

Заранее спасибо!

Ответы [ 5 ]

14 голосов
/ 17 января 2012

Используйте это простое выражение 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

Объяснение

Этот метод известен как метод двойного перевода , впервые предложенный Майклом Кей. Он состоит из двух вложенных вызовов функции translate():

  1. Внутренний translate(). Это производит все символы строки, кроме цифр.

  2. Наружный translate(). Это удаляет из строки все символы, созданные внутренним translate(). Остаются только нужные символы (цифры).

8 голосов
/ 17 января 2012

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>.

Идея translate Newtover (для XSLT 1.0) будет выглядеть следующим образом:

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

Но если ваш вводсодержит несколько чисел, которые просто объединят их.

2 голосов
/ 17 января 2012

Привет, это даст результаты, которые вы требуете! он проверяет каждый символ, а затем проверяет, является ли он числом.

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>
2 голосов
/ 17 января 2012

Хрупким, но возможным решением в простом XSLT 1.0 было бы использование композиции translate (чтобы сделать все нечисловые значения пустыми строками или пробелами) и normalize-space (чтобы обрезать оставшиеся пробелы, хотя translate может быть достаточно).Это, безусловно, будет работать, только если в строке нет других числовых значений.И, в настоящее время я не могу проверить, translate может работать, только если ваша строка содержит символы ascii.

XSLT 2.0 имеет несколько функций регулярного выражения.Если ваш xslt-процессор позволяет использовать расширения EXSLT, он также содержит функции регулярных выражений или вы можете токенизировать вашу строку по пробелам и предоставлять непустой шаблон только для числового токена.

ps Мне жаль, что я делаюне предоставлять никаких ссылок, трудно получить с устройства.

0 голосов
/ 04 февраля 2019

Ниже приведен вывод вышеприведенного решения XSLT v1, однако это специально для старшего числа, в отличие от встроенного в середине строки. Это также учитывает разбор с плавающей запятой или целочисленный. (Лично я нахожу это полезным для разделения единиц от значений, таких как «80 мг» или «128,4 мм2», где единицей является «мм2», а значение «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: []
...