2016-03-29 1 views
3

У меня есть XML, как это,XSLT - анализ следующих последовательных узлов

<doc> 
    <para>texttext<page>1</page>texttext<page>1</page>texttext</para> 
    <para>texttext<page>1</page><page>2</page>texttext</para> 
    <para>texttext<page>1</page><page>2</page><page>3</page>texttext<page>4</page><page>5</page><page>6</page>texttext</para> 
    <para>texttext<page>1</page><page>2</page><page>3</page><page>4</page>texttext</para> 
</doc> 

Мне нужно преобразовать <page> узлы <link> с помощью XSL преобразования и следующие правила должны быть рассмотрены,

  • если только один узел <page> (не следует ни одному узлу страницы), он просто преобразуется в <link>
  • если два узла <page> размещены последовательно (сценарий 2 за m выше примера) ',' необходимо добавить между выводами <link> узлов
  • , если 3 или более <page> узлов, помещенных последовательно (пример 3 и 4 из примера выше), просто добавляет первое и последнее содержимое узла страницы, разделенное символом '-'

Таким образом, выход должен быть таким,

<doc> 
    <para>texttext<link>1</link>texttext<link>1</link>texttext</para> 
    <para>texttext<link>1</link>,<link>2</link>texttext</para> 
    <para>texttext<link>1</link>-<link>3</link>texttext<link>4</link>-<link>6</link>texttext</para> 
    <para>texttext<link>1</link>-<link>4</link>texttext</para> 
</doc> 

Я написал следующее XSL для выполнения этой задачи,

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

    <xsl:template match="page"> 
     <link> 
      <xsl:apply-templates/> 
     </link> 
    </xsl:template> 

    <xsl:template match="page[following-sibling::node()[1][self::page]]"> 
     <link> 
      <xsl:apply-templates/> 
     </link> 
     <xsl:text>,</xsl:text> 
     <link> 
      <xsl:apply-templates select="following-sibling::*[1]"/> 
     </link> 
    </xsl:template> 

    <xsl:template match="page[following-sibling::node()[1][self::page]][following-sibling::node()[2][self::page]]"> 
     <link> 
      <xsl:apply-templates/> 
     </link> 
     <xsl:text>-</xsl:text> 
     <link> 
      <xsl:apply-templates select="following-sibling::*[2]"/> 
     </link> 
    </xsl:template> 

, но этот метод не является woking как, он добавляет ',', когда появляются 3 последовательных узла <page>, и если появляется больше узлов <page>, этот метод неэффективен.

Может кто-нибудь предложить хороший метод в XSLT для анализа следующих братьев и сестер сформировать и XSLT сделать эту задачу ..

ответ

2
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> 
    <xsl:output method="xml" encoding="UTF-8" indent="yes" /> 

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

    <xsl:template match="page[not(preceding-sibling::node()[1][self::page])]"> 
     <xsl:variable name="pages" select="following-sibling::page[ 
      preceding-sibling::node()[1][self::page] 
      and generate-id(current()) = generate-id(preceding-sibling::page[ 
       not(preceding-sibling::node()[1][self::page]) 
      ][1]) 
     ]" /> 
     <xsl:apply-templates select="." mode="link" /> 
     <xsl:if test="count($pages) = 1">,</xsl:if> 
     <xsl:if test="count($pages) &gt; 1">-</xsl:if> 
     <xsl:apply-templates select="$pages[last()]" mode="link" /> 
    </xsl:template> 
    <xsl:template match="page" /> 

    <xsl:template match="page" mode="link"> 
     <link> 
      <xsl:apply-templates select="@*|node()"/> 
     </link> 
    </xsl:template> 
</xsl:transform> 

результат

<doc> 
    <para>texttext<link>1</link>texttext<link>1</link>texttext</para> 
    <para>texttext<link>1</link>,<link>2</link>texttext</para> 
    <para>texttext<link>1</link>-<link>3</link>texttext<link>4</link>-<link>6</link>texttext</para> 
    <para>texttext<link>1</link>-<link>4</link>texttext</para> 
</doc> 

Здесь

<xsl:template match="page[not(preceding-sibling::node()[1][self::page])]"> 

матчи любых <page>, который начинает «диапазон» последовательных страниц.

Выбор остальных страниц последовательного диапазона немного сложно, но можно сделать так:

  • всех следующих родственных страниц выберите те, которые
    • сами непосредственно предшествует <page> (т.е. «часть диапазона») и
    • ближайшие предшествующей <page>, что сам по себе не непосредственно предшествуют другое <page> (то есть "ближайший <page>, начинающийся с диапазона"), идентичен текущему узлу.

Учитывая, что мы только обрабатывать <page> узлы, которые начинаются диапазон в этом шаблоне, это составляет «является частью текущего диапазона».

В терминах XPath, как показано выше:

following-sibling::page[ 
    preceding-sibling::node()[1][self::page] 
    and generate-id(current()) = generate-id(preceding-sibling::page[ 
     not(preceding-sibling::node()[1][self::page]) 
    ][1]) 
]