Счетчик Гобала в XSLT или альтернативное решение? - PullRequest
1 голос
/ 13 июля 2010

Это мой Source-XML. Изначально это Word-ML, который был уменьшен до собственной структуры. Элементы с именем «aaa» могут иметь любое имя. Проблема в обработке сносок:

<root>
  <doc>
    <comment>text text text <footnote id="1" > text text text</comment>
    <aaa>text text text</aaa>
    <aaa>text text text<footnote id="2" /> text text text </aaa>
    <aaa>text text text<aaa/> text <footnote id="3" symbol="*"/></aaa>
    <aaa>text text text text</aaa>
    <aaa>text text text text<aaa>text text text<footnote id="4"  /></aaa></aaa>
 <aaa>text text text text<aaa>text text text<footnote id="4"  /></aaa></aaa>
 <aaa>text text text text<aaa>text text text<footnote id="5"  /></aaa></aaa>
    <aaa>text text text</aaa>
  </doc>
</root>

Мне нужно преобразовать этот Source-XML в другой XML. Одна вещь, которую я должен сделать, это заменить сноски на соответствующий номер.

Но нельзя использовать только ID-атрибут. Идентификатор - это только внутренний номер. Сноски должны быть прогрессивными и при соблюдении следующих условий:

  • Условие 1: «сноски», являющиеся потомками узла «comment», следует игнорировать. весь узел "комментарий" игнорируется.
  • Условие 2: «сноски», которые имеют символ-атрибут, не учитываются (я должен показать символ, а не число)
  • Условие 3: возможно, что некоторые заметки имеют одинаковый идентификатор (только низкий процент, но иногда есть больше ссылок на одну и ту же сноску).

Вывод должен выглядеть следующим образом (структура уже не та, интересна только обработка сносок):

<root>
  <doc>
    <aaa>text text text</aaa>
    <aaa>text text text[1] text text text </aaa>
    <aaa>text text text<aaa/> text [*]</aaa>
    <aaa>text text text text</aaa>
    <aaa>text text text text<aaa>text text text[2]</aaa></aaa>
 <aaa>text text text text<aaa>text text text[2]</aaa></aaa>
 <aaa>text text text text<aaa>text text text[3]</aaa></aaa>
    <aaa>text text text</aaa>
  </doc>
</root>

Моей первой мыслью было иметь глобальную контр-переменную, которую я увеличиваю в соответствии с условиями. Но поскольку переменные в XSLT являются неизменяемыми, на самом деле это не вариант.

Я также пытался подсчитать предыдущие сноски, которые находятся перед текущей сноской.

        <xsl:template match="footnote">
         <xsl:call-template name="getFootnoteNumber">
          <xsl:with-param name="footNodeId" select="@id"/>
         </xsl:call-template>
        </xsl:template>

    <!-- simple template which only counts the footnotes
    that occur before the current footnode 
    the conditions 1, 2 and 3 are not yet included -->
        <xsl:template name="getFootnoteNumber">
           <xsl:param name="footNodeId"/>
           <xsl:value-of select="count(//footnote[position()&lt;=$footNodeId])"></xsl:value-of>     
    </xsl:template>
    <!-- i mostly get value "0", 
    or other strange numbers: for footNodeID=45 i get value 75, 
    doesn't really work-->

Есть ли возможность разработать глобальный счетчик?

Или я должен пойти другим путем, считая предыдущие сноски? Хотя я действительно не знаю, как выполнить условие 3.

Привет и спасибо за любой ответ cpt.oneeye

Ответы [ 2 ]

2 голосов
/ 13 июля 2010

Эта таблица стилей:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:key name="foot" match="footnote[not(ancestor::comment)][not(@symbol)]" use="@id"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="footnote[ancestor::comment]" priority="1" />
    <xsl:template match="footnote[@symbol]">
        <xsl:value-of select="concat('[',@symbol,']')"/>
    </xsl:template>
    <xsl:template match="footnote">
        <xsl:value-of select="concat('[',count(key('foot',@id)[1]/preceding::footnote[generate-id(.)=generate-id(key('foot',@id)[1])])+1,']')"/>
    </xsl:template>
</xsl:stylesheet>

При правильном вводе:

<root>
    <doc>
        <comment>text text text <footnote id="1" /> text text text</comment>
        <aaa>text text text</aaa>
        <aaa>text text text <footnote id="2" /> text text text</aaa>
        <aaa>text text text <aaa/>text <footnote id="3" symbol="*"/></aaa>
        <aaa>text text text text</aaa>
        <aaa>text text text text <aaa>text text text <footnote id="4"  /></aaa></aaa>
        <aaa>text text text text <aaa>text text text <footnote id="4"  /></aaa></aaa>
        <aaa>text text text text <aaa>text text text <footnote id="5"  /></aaa></aaa>
        <aaa>text text text</aaa>
    </doc>
</root>

Результат:

<root>
    <doc>
        <comment>text text text  text text text</comment>
        <aaa>text text text</aaa>
        <aaa>text text text [1] text text text</aaa>
        <aaa>text text text <aaa></aaa>text [*]</aaa>
        <aaa>text text text text</aaa>
        <aaa>text text text text <aaa>text text text [2]</aaa></aaa>
        <aaa>text text text text <aaa>text text text [2]</aaa></aaa>
        <aaa>text text text text <aaa>text text text [3]</aaa></aaa>
        <aaa>text text text</aaa>
    </doc>
</root>

Редактировать : пропустить брекеты. Далее я опубликую ответ без предшествующей оси.

1 голос
/ 13 июля 2010

Решение XSLT 2.0:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes"/>

 <xsl:key name="kPosById" match="@pos" use="../@id"/>

 <xsl:variable name="vdistinctFootnotes">
  <xsl:for-each-group group-by="@id" select=
    "/*/*/*[not(self::comment)]//footnote[not(@symbol)]">

    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <xsl:attribute name="pos" select="position()"/>
    </xsl:copy>
  </xsl:for-each-group>
 </xsl:variable>

    <xsl:template match="node()|@*">
      <xsl:copy>
         <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
    </xsl:template>

    <xsl:template match="footnote">
      <xsl:value-of select=
      "concat('[', key('kPosById', @id, $vdistinctFootnotes), ']')"/>
    </xsl:template>

    <xsl:template match="footnote[@symbol]">
     <xsl:value-of select="concat('[', @symbol, ']')"/>
    </xsl:template>

    <xsl:template match="footnote[ancestor::comment]"/>
</xsl:stylesheet>

когда это преобразование применяется к предоставленному документу (исправлено, чтобы быть исправленным):

<root>
  <doc>
    <comment>text text text <footnote id="1" /> text text text</comment>
    <aaa>text text text</aaa>
    <aaa>text text text<footnote id="2" /> text text text </aaa>
    <aaa>text text text<aaa/> text <footnote id="3" symbol="*"/></aaa>
    <aaa>text text text text</aaa>
    <aaa>text text text text<aaa>text text text<footnote id="4"  /></aaa></aaa>
 <aaa>text text text text<aaa>text text text<footnote id="4"  /></aaa></aaa>
 <aaa>text text text text<aaa>text text text<footnote id="5"  /></aaa></aaa>
    <aaa>text text text</aaa>
  </doc>
</root>

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

<root>
  <doc>
    <comment>text text text  text text text</comment>
    <aaa>text text text</aaa>
    <aaa>text text text[1] text text text </aaa>
    <aaa>text text text<aaa/> text [*]</aaa>
    <aaa>text text text text</aaa>
    <aaa>text text text text<aaa>text text text[2]</aaa></aaa>
 <aaa>text text text text<aaa>text text text[2]</aaa></aaa>
 <aaa>text text text text<aaa>text text text[3]</aaa></aaa>
    <aaa>text text text</aaa>
  </doc>
</root>
...