Обтекание нескольких последовательностей элементов списка с использованием XSL-преобразования (XML в XML) - PullRequest
4 голосов
/ 04 июня 2011

У меня есть некоторый входной длинный (около 3 тыс. Строк) XML-документ, который обычно выглядит следующим образом:

<chapter someAttributes="someValues">
    <title>someTitle</title>

    <p>multiple paragraphs</p>
    <p>...</p>

    <li>
        <p>- some text</p>
    </li>
    <li>
        <p>- some other text</p>
    </li>
    <!-- another li elements -->

    <p>multiple other paragraphs</p>
    <p>...</p>

    <li>
        <p>1. some text</p>
    </li>
    <li>
        <p>2. some other text</p>
    </li>
    <!-- another li elements -->

    <p>multiple other paragraphs</p>
    <p>...</p>

    <!-- there are other elements such as table, illustration, ul etc. -->  
</chapter>

Я хочу обернуть каждый разбросанный (я имею в виду между абзацами,таблицы, иллюстрации и т. д.) последовательность из li элементов с ol или ul элементами в зависимости от некоторых семантических и возвращаемых обернутых XML.

  • если первый символ в абзацеравно -, то должно быть ul с атрибутом mark="DASH"
  • , если абзацы начинаются с 1., 2., 3. и т. д., тогда я хочу ol с numeration="ARABIC"

Например (это всего лишь одна последовательность):

<ul mark="DASH">
    <li>
        <p> some text</p>
    </li>
    <li>
        <p> some other text</p>
    </li>
<ul>

Как вы видите далее, мне нужно вырезать"пометить символ (ы)"из всех абзацев, то есть - или 1., 2., 3. и т. д.

Этот входной XML более сложный, чем я описал (вложенные последовательности, внутренние последовательности в элементах таблицы), ноЯ ищу какую-то идею, особенно как поймать и обработать определенную последовательность с такой семантикой.

Я хочу выводить XML с точно таким же порядком, только с обернутыми li элементами.XSLT 2.0 / EXSLT доступны при необходимости.

Ответы [ 2 ]

3 голосов
/ 04 июня 2011

Вот таблица стилей XSLT 2.0:

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

  <xsl:output indent="yes"/>

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

  <xsl:template match="chapter">
    <xsl:copy>
      <xsl:for-each-group select="*" group-adjacent="boolean(self::li)">
        <xsl:choose>
          <xsl:when test="current-grouping-key() and ./p[1][starts-with(., '-')]">
            <ul mark="DASH">
              <xsl:apply-templates select="current-group()"/>
            </ul>
          </xsl:when>
          <xsl:when test="current-grouping-key() and ./p[1][matches(., '[0-9]\.')]">
            <ol numeration="arabic">
              <xsl:apply-templates select="current-group()"/>
            </ol>
          </xsl:when>
          <xsl:otherwise>
            <xsl:copy-of select="current-group()"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="li/p/text()[1]">
    <xsl:value-of select="replace(., '^(-|[0-9]\.)', '')"/>
  </xsl:template>

</xsl:stylesheet>

Когда я использую Saxon 9.3 с этой таблицей стилей и примером ввода

<chapter someAttributes="someValues">
    <title>someTitle</title>

    <p>multiple paragraphs</p>
    <p>...</p>

    <li>
        <p>- some text</p>
    </li>
    <li>
        <p>- some other text</p>
    </li>
    <!-- another li elements -->

    <p>multiple other paragraphs</p>
    <p>...</p>

    <li>
        <p>1. some text</p>
    </li>
    <li>
        <p>2. some other text</p>
    </li>
    <!-- another li elements -->

    <p>multiple other paragraphs</p>
    <p>...</p>

    <!-- there are other elements such as table, illustration, ul etc. -->  
</chapter>

Я получаю следующий вывод:

<?xml version="1.0" encoding="UTF-8"?>
<chapter>
   <title>someTitle</title>
   <p>multiple paragraphs</p>
   <p>...</p>
   <ul mark="DASH">
      <li>
        <p> some text</p>
      </li>
      <li>
        <p> some other text</p>
      </li>
   </ul>
   <p>multiple other paragraphs</p>
   <p>...</p>
   <ol numeration="arabic">
      <li>
        <p> some text</p>
      </li>
      <li>
        <p> some other text</p>
      </li>
   </ol>
   <p>multiple other paragraphs</p>
   <p>...</p>
</chapter>
1 голос
/ 05 июня 2011

Вот полное функциональное решение, без какого-либо процедурного подхода, такого как xsl:for-each-group и xsl:if.

XSLT 2.0 , протестированное в Saxon-B9.0.0.1J

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output indent="yes" method="html"/>

    <xsl:strip-space elements="*"/>

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

    <!-- override dash list elements -->
    <xsl:template match="li[(name(preceding-sibling::*[position()=1]) 
        != name(current())) 
        and matches(.,'^-')]">

        <ul mark="DASH">
            <li><xsl:apply-templates/></li>
            <!-- apply recursive template for adjacent nodes -->
            <xsl:apply-templates select="following-sibling::*[1][name()
                =name(current())]" mode="next"/>
        </ul>
    </xsl:template>

    <!-- override numeration list elements -->
    <xsl:template match="li[(name(preceding-sibling::*[position()=1]) 
        != name(current())) 
        and matches(.,'^[0-9]\.')]">
        <ol numeration="ARABIC">
            <li><xsl:apply-templates/></li>
            <xsl:apply-templates select="following-sibling::*[1][name()
                =name(current())]" mode="next"/>
        </ol>
    </xsl:template>

    <!-- recursive template for adjacent nodes -->
    <xsl:template match="*" mode="next">
        <li><xsl:apply-templates/></li>
        <xsl:apply-templates select="following-sibling::*[1][name()
            =name(current())]" mode="next"/>
    </xsl:template>

    <!-- remove marks/numeration from first text node -->
    <xsl:template match="li/p/text()[1]">
        <xsl:value-of select="replace(., '^(-|[0-9]\.)\s+', '')"/>
    </xsl:template>

</xsl:stylesheet>

При применении к вашему входу получается:

<chapter someAttributes="someValues">
   <title>someTitle</title>
   <p>multiple paragraphs</p>
   <p>...</p>
   <ul mark="DASH">
      <li>
         <p>some text</p>
      </li>
      <li>
         <p>some other text</p>
      </li>
   </ul>
   <!-- another li elements -->
   <p>multiple other paragraphs</p>
   <p>...</p>
   <ol numeration="ARABIC">
      <li>
         <p>some text</p>
      </li>
      <li>
         <p>some other text</p>
      </li>
   </ol>
   <!-- another li elements -->
   <p>multiple other paragraphs</p>
   <p>...</p>
   <!-- there are other elements such as table, illustration, ul etc. -->
</chapter>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...