Количество ключевых слов в xslt

Я тоже и смотрю на тип механизма подсчета ключевых слов, который был опубликован здесь Word Frequency Counter in XSLT:

Моя проблема в том, что мои ключевые слова могут состоять из нескольких слов, например:

<xsl:variable name="stopwords" 
select="('audio codec', 'dual audio', 'audio switch' )"/>

Я играл с кодом из приведенного выше вопроса и имел что-то вроде этого:

<xsl:stylesheet
   version="2.0"
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" indent="yes"/>

<xsl:template match="/">   

<xsl:variable name="stopwords" 
  select="('audio codec', 'dual audio', 'audio switch' )"/>
     <wordcount>
        <xsl:for-each-group group-by="." select="
            for $w in //text()/tokenize(., '\W+')[not(.=$stopwords)] return $w">
            <word word="{current-grouping-key()}" frequency="{count(current-group())}"/>
        </xsl:for-each-group>
     </wordcount>
</xsl:template>

Certainly tokenizing with the '\W+' breaks this into words, but then that won't match my stopwords, as they are and can be multiple words.

Может ли кто-нибудь предложить элегантный способ подсчета слов, когда ключевые слова могут иметь несколько слов?

Спасибо за любую помощь в этом!

Расс


person Russ Urquhart    schedule 20.10.2014    source источник
comment
Использование стоп-фраз несовместимо со счетом слов. Вы собираетесь начать считать фразы вместо слов? Затем рассмотрим w1 w2 w3 Хотите ли вы посчитать (w1, w2, w3) или (w1 w2, w2 w3) или (w1 w2 w3) или объединение всех этих множеств?   -  person kjhughes    schedule 20.10.2014
comment
Если вы по-прежнему собираетесь считать слова, а не фразы, но хотите, чтобы ваши стоп-фразы не влияли на подсчет, возможно, вам будет лучше удалить стоп-фразы перед выполнением подсчета.   -  person kjhughes    schedule 20.10.2014
comment
Сорри, что ввел в заблуждение. Мои стоп-слова на самом деле являются фразами, экземпляры которых я хотел подсчитать. Я мог придумать способы перебора, проверки каждой фразы, но надеялся, что есть аналогичный элегантный способ подсчета вхождений фраз, как в этом примере для отдельных слов.   -  person Russ Urquhart    schedule 20.10.2014
comment
kjhughes, твой ответ только что удалили. Это сделали вы или кто-то другой?   -  person Russ Urquhart    schedule 20.10.2014
comment
Пришлось исправить для обработки нескольких keyphrases в текстовом узле. Сейчас восстановлен. Я надеюсь, что это помогает.   -  person kjhughes    schedule 21.10.2014


Ответы (2)


Учитывая этот входной XML:

<?xml version="1.0" ?>
<a>
  <b>match: audio switch</b>
  <c>no match:</c>
  <d>no match: audiocodec</d>
  <e attr="no match: audio codec"/>
  No match:  Audio switch/dual AUDIO
  Match x2:  audio switch/dual audio/audio switch
  No match: <f>xxx audio</f><g>codec yyy</g>
</a>

Этот XSLT:

<xsl:stylesheet version="2.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:f="http://example.com/f"
                exclude-result-prefixes="f">
  <xsl:output method="xml" encoding="UTF-8" indent="yes"/>

  <xsl:variable name="keyphrases" 
                select="('audio codec', 'dual audio', 'audio switch' )"/>

  <xsl:template match="/">
    <xsl:variable name="docText" select="string-join(//text(), '|')"/>
    <keyphrases>
      <xsl:for-each select="$keyphrases">
        <keyphrase phrase="{.}" count="{f:substr-count($docText, .)}"/>
      </xsl:for-each>
    </keyphrases>
  </xsl:template>

  <xsl:function name="f:substr-count">
    <xsl:param name="s"/>
    <xsl:param name="substr"/>
    <xsl:value-of select="if ($s and $substr and contains($s, $substr))
                          then f:substr-count(substring-after($s, $substr), $substr)+1
                          else 0"/>
  </xsl:function>

</xsl:stylesheet>

Создает этот выходной XML, который подсчитывает количество ваших "стоп" слов (которые я переименовал в keyphrases):

<?xml version="1.0" encoding="UTF-8"?>
<keyphrases>
   <keyphrase phrase="audio codec" count="0"/>
   <keyphrase phrase="dual audio" count="1"/>
   <keyphrase phrase="audio switch" count="3"/>
</keyphrases>
person kjhughes    schedule 20.10.2014

Разве это не может быть проще? Например:

    <xsl:for-each select="$stopwords">
        <word word="{.}" frequency="{count(tokenize($all-text, .)) - 1}"/>
    </xsl:for-each>

Демонстрация:
http://xsltransform.net/94hvTyW
http://xsltransform.net/94hvTyW/1

Чтобы предотвратить ложноположительные совпадения, например. «двойное аудио», соответствующее «индивидуальным аудиограммам», вы можете использовать:

tokenize($all-text, concat('\W', ., '\W'))

К сожалению, регулярное выражение XPath не имеет привязки для границы слова (см.: https://stackoverflow.com/a/25464233/3016153), поэтому может быть безопаснее добавлять пробел перед переменной $all-text.

person michael.hor257k    schedule 21.10.2014
comment
Мне нравится проще, но этот считает <f>xxx audio</f><g>codec yyy</g> совпадающим аудиокодеком, хотя, вероятно, не должен. - person kjhughes; 21.10.2014
comment
@kjhughes Вероятно, нет, но это легко исправить, используя другой символ-разделитель (вместо пробела) в начальном соединении строк. - person michael.hor257k; 21.10.2014