подсчитать количество вхождений строки в XML с использованием XSLT - PullRequest
5 голосов
/ 13 июля 2011

Я хочу вычислить количество вхождений строки в конкретном узле в документе XML с использованием XSLT. Рассмотрим этот пример

 <mainNode>
<book>
    <price> 100 </price>
    <city> chennai </city>
    <list>
        <language> c java ruby </language>
    </list>
</book>

<book>
    <price> 200 </price>
    <city> banglore </city>
    <list>
        <language> c java </language>
    </list>
</book>

<book>
    <price> 300 </price>
    <city> delhi </city>
    <list>
        <language> java ruby </language>
    </list>
</book>
</mainNode>      

Здесь я хочу посчитать вхождения "java"

Я хочу вывод, как это :: Java - 3

Как это сделать ??? есть идеи ???

Ответы [ 4 ]

7 голосов
/ 13 июля 2011

Использование :

count(/*/*/list/language[contains(., 'java')])

Полное преобразование XSLT :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:template match="/">
     java -- <xsl:value-of select=
       "count(/*/*/list/language[contains(., 'java')]) "/>
 </xsl:template>
</xsl:stylesheet>

при применении к предоставленному документу XML:

<mainNode>
    <book>
        <price> 100 </price>
        <city> chennai </city>
        <list>
            <language> c java ruby </language>
        </list>
    </book>
    <book>
        <price> 200 </price>
        <city> banglore </city>
        <list>
            <language> c java </language>
        </list>
    </book>
    <book>
        <price> 300 </price>
        <city> delhi </city>
        <list>
            <language> java ruby </language>
        </list>
    </book>
</mainNode>

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

 java -- 3

Обновление :

Если мы хотим подсчитать все вхождений строки - не только все узлы, которые содержат строку - вот как это сделать:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes"/>
    <xsl:param name="pWord" select="' java '"/>

    <xsl:template match="/">
        <xsl:variable name="vResult">
            <xsl:apply-templates/>
        </xsl:variable>
        <xsl:value-of select="concat($pWord, '--- ')"/>
        <xsl:value-of select="string-length($vResult)"/>
    </xsl:template>

    <xsl:template match="list/language" name="countWord">
        <xsl:param name="pText" select="."/>

        <xsl:if test="contains($pText, $pWord)">
            <xsl:text>X</xsl:text>
            <xsl:call-template name="countWord">
                <xsl:with-param name="pText"
                 select="concat(' ', substring-after($pText, $pWord))"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

    <xsl:template match="text()"/>
</xsl:stylesheet>

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

<mainNode>
    <book>
        <price> 100 </price>
        <city> chennai </city>
        <list>
            <language> c java ruby </language>
        </list>
    </book>
    <book>
        <price> 200 </price>
        <city> banglore </city>
        <list>
            <language> c java </language>
        </list>
    </book>
    <book>
        <price> 300 </price>
        <city> delhi </city>
        <list>
            <language> java java ruby </language>
        </list>
    </book>
</mainNode>

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

 java --- 4
2 голосов
/ 13 июля 2011

возможно, вы можете попробовать этот шаблон XSL для подсчета подстрок :

<xsl:template name="substring-count">
  <xsl:param name="string"/>
  <xsl:param name="substr"/>
  <xsl:choose>
    <xsl:when test="contains($string, $substr) and $string and $substr">
      <xsl:variable name="rest">
        <xsl:call-template name="substring-count">
          <xsl:with-param name="string" select="substring-after($string, $substr)"/>
          <xsl:with-param name="substr" select="$substr"/>
        </xsl:call-template>
      </xsl:variable>
      <xsl:value-of select="$rest + 1"/>
    </xsl:when>
    <xsl:otherwise>0</xsl:otherwise>
  </xsl:choose>
</xsl:template>

Использование:

<xsl:call-template name="substring-count">
  <xsl:with-param name="string" select="'mary had a little lamb'" />
  <xsl:with-param name="substr" select="'lamb'" />
</xsl:call-template>
1 голос
/ 13 июля 2011

Попробуйте это в выражении <xsl:value-of>:

count(//language[contains(concat(' ',.,' '), ' java ')])

Если ваша структура документа относительно статична или у вас есть узлы, называемые language в других местах, которые служат другой цели, вы можете заменить //language на /mainNode/book/list/language.

Бит concat может показаться немного запутанным, но, убедившись, что в начале и конце текста, который вы просматриваете, есть пробел, и выполнив поиск ' java ' с пробелом по обе стороны, вы выиграли ' неправильно включают другие термины, которые включают java, например javascript.

Если 'java' может существовать более одного раза в узле, тогда вам нужно использовать рекурсивный шаблон. Вот один из способов:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" />
  <xsl:template match="/">
    <xsl:variable name="list">
      <xsl:for-each select="//language">
        <xsl:call-template name="count">
          <xsl:with-param name="lang">java</xsl:with-param>
        </xsl:call-template>
      </xsl:for-each>
    </xsl:variable>
    <xsl:value-of select="concat('java -- ',string-length($list))" />
  </xsl:template>

  <xsl:template name="count">
    <xsl:param name="lang" />
    <xsl:param name="text" select="text()" />
    <xsl:if test="contains(concat(' ',$text,' '),concat(' ',$lang,' '))">
      <xsl:text>0</xsl:text>
      <xsl:call-template name="count">
        <xsl:with-param name="lang" select="$lang" />
        <xsl:with-param name="text" select="substring-after($text,$lang)" />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

По сути, это создает строку из 0, по одному для каждого вхождения java, а затем просто использует длину этой строки.

Если у вас есть возможность использовать XSLT 2.0, вы можете создать функцию, которая подсчитывает количество вхождений в строке, и использовать <xsl:value-of select="sum(mycountfunction(//language))" /> или что-то подобное.

Как я указывал в комментарии к вашему вопросу, лучшая разработка исходного XML очень помогла бы; ничего из этого не требуется, если каждое вхождение языка имеет свой собственный элемент. Конечно, это может быть вне вашего контроля, но если у вас есть возможность изменить это (или убедить поставщика изменить это), я настоятельно рекомендую это.

0 голосов
/ 31 мая 2017
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...