Как найти все числа в строке

Ich versuche mit einer Funktion sämtliche Zahlen aus einem Element oder String zu ermitteln. Dabei soll die Anzahl der Zahlen und ihre Stelligkeit egal sein. Folgende Funktion habe ich bislang geschrieben:

<xsl:function name="itp:find_num">
<xsl:param name="tmp"/>
<xsl:if test="matches($tmp,'\d+')">
    <xsl:analyze-string select="$tmp" regex="{'\d+'}">
        <xsl:matching-substring>
             <xsl:sequence select="."/>
        </xsl:matching-substring>
        <xsl:non-matching-substring>
            <xsl:value-of select="''"/>
        </xsl:non-matching-substring>
    </xsl:analyze-string>
</xsl:if>
</xsl:function>

Beispiel XML:

<address>street 12, 12345 town<address>

Bei dem Funktionsaufruf soll dann die entsprechende Zahl ausgewählt werden können:

...select="itp:find_num(address)[2]"/>

Zum Beispiel die 2 für die Postleitzahl. Das Problem ist nun, dass in der Sequence auch leere Werte stehen, so dass ich in der Praxis die Postleitzahl nur mit [4] erreiche.

Gibt es eine elegantere Möglichkeit meine Problem zu lösen? Und wenn nicht, wie lösche ich die leeren Elemente aus der Sequence ??

Теперь на английском :-)

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

Вот моя функция:

<xsl:function name="itp:find_num">
<xsl:param name="tmp"/>
<xsl:if test="matches($tmp,'\d+')">
    <xsl:analyze-string select="$tmp" regex="{'\d+'}">
        <xsl:matching-substring>
        <xsl:if test=". != ''">
            <xsl:sequence select="."/>
        </xsl:if>
        </xsl:matching-substring>
        <xsl:non-matching-substring>
            <xsl:value-of select="''"/>
        </xsl:non-matching-substring>
    </xsl:analyze-string>
</xsl:if>
</xsl:function>

Пример XML

<address>street 12, 12345 town<address>

Когда я вызываю функцию, которую хочу выбрать, какой номер я хочу выбрать:

...select="itp:find_num(address)[2]"/>

Пример [2] для почтового индекса. Моя проблема заключается в том, что в последовательности есть пустые элементы, поэтому я должен выбрать [4], чтобы получить почтовый индекс.

Есть ли более простой способ решить мою проблему? Или есть способ удалить все пустые элементы в этой последовательности ??

Спасибо :-)


person Christian Manthey    schedule 08.05.2013    source источник
comment
Christian Manthey, Возможно, вас заинтересует более простое, короткое и чистое решение XPath.   -  person Dimitre Novatchev    schedule 08.05.2013


Ответы (2)


Я бы написал функцию как

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:mf="http://example.org/mf"
  exclude-result-prefixes="xs mf">

<xsl:function name="mf:find_num" as="xs:integer*">
  <xsl:param name="input" as="xs:string"/>
  <xsl:analyze-string select="$input" regex="[0-9]+">
    <xsl:matching-substring>
      <xsl:sequence select="xs:integer(.)"/>
    </xsl:matching-substring>
  </xsl:analyze-string>
</xsl:function>

<xsl:template match="address">
  <xsl:value-of select="mf:find_num(.)" separator=", "/>
</xsl:template>

</xsl:stylesheet>

Конечно, преобразование в xs:integer необязательно, если вы хотите, чтобы функция возвращала последовательность строк, содержащих цифры, вы просто измените ее на

<xsl:function name="mf:find_num" as="xs:string*">
  <xsl:param name="input" as="xs:string"/>
  <xsl:analyze-string select="$input" regex="[0-9]+">
    <xsl:matching-substring>
      <xsl:sequence select="."/>
    </xsl:matching-substring>
  </xsl:analyze-string>
</xsl:function>
person Martin Honnen    schedule 08.05.2013
comment
Что ж, это было довольно просто. Не знал, что несоответствующая подстрока не нужна. Возможно, я неправильно понял функцию строки анализа. Большое спасибо, это именно то, что я искал :-) - person Christian Manthey; 08.05.2013

Нет необходимости в сложной xsl:analyze-string обработке.

Этот однострочник XPath:

   for $i in tokenize($pStr, '[^0-9]+')[.]
    return xs:integer($i)

производит желаемую последовательность целых чисел в строке:

12 12345

Вот полное преобразование:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:my="my:my">
 <xsl:output method="text"/>

 <xsl:template match="/*">
  <xsl:sequence select="my:nums(.)"/>
 </xsl:template>

 <xsl:function name="my:nums" as="xs:integer*">
  <xsl:param name="pStr" as="xs:string"/>

  <xsl:sequence select=
  "for $i in tokenize($pStr, '[^0-9]+')[.]
    return xs:integer($i)"/>
 </xsl:function>
</xsl:stylesheet>

Когда это преобразование применяется к предоставленному XML-документу:

<address>street 12, 12345 town</address>

Получен желаемый правильный результат:

12 12345

Еще проще, однострочник XPath 3.0:

tokenize($pStr, '[^0-9]+')[.] ! xs:integer(.)
person Dimitre Novatchev    schedule 08.05.2013
comment
Спасибо за ответ, но я получаю эту ошибку: последовательность из более чем одного элемента недопустима в результате функции itp: find_num () - person Christian Manthey; 08.05.2013
comment
@ChristianManthey, Скорее всего у вас ошибка копирования / вставки. Обратите внимание, как функция определена в ответе: as="xs:integer*". Я предполагаю, что вы пропустили атрибут as или неправильно его переписали. - person Dimitre Novatchev; 08.05.2013
comment
Вот и все. Я забыл *. Отличное решение! Спасибо! - person Christian Manthey; 08.05.2013