XSLT: разбить несгруппированные данные на куски - PullRequest
2 голосов
/ 19 октября 2011

Мне нужно превратить

   <question>
      <static><![CDATA[Static Data]]></static>

      <debit-row />
      <debit-row />
      <credit-row />

      <header><![CDATA[Header HTML 1]]></header>
      <debit-row />
      <debit-row />
      <credit-row />
   </question>

в

<p>Static Data</p>
<ul>
   <li>
      <table>
         <tr><td> debit row </td></tr>
         <tr><td> credit row </td></tr>
         <tr><td> credit row </td></tr>
      </table>
   </li>
   <li> Header HTML 1
      <table>
         <tr><td> debit row </td></tr>
         <tr><td> debit row </td></tr>
         <tr><td> credit row </td></tr>
      </table>
   </li>
</ul>

По сути, заголовок или строка дебета указывают на начало нового чанка.Каждый кусок - это элемент списка.Каждый набор или строки - это таблица (как правило, кредитные строки всегда идут последними, поэтому легко определить, когда начинать таблицу).

XSLT и XPATH кажутся очень сложными, и у меня очень тяжелые временапоиск всего, что я хочу сделать, поэтому, если у кого-то есть отличная ссылка, я был бы также признателен за это.

Я начал с этого xsl:

<xsl:template match="question">
   <xsl:apply-templates select="static|header|debit-row[preceding-sibling::*[1] != header]" />
</xsl:template>

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

Даже если я заставлю это работать, мне нужно найти способ сказать "Откройте <ul>, если это самый первый заголовок или строка дебета", и яне уверен, как это сделать при применении шаблона заголовка / дебет-строки.У каждого дебетового ряда есть свой собственный xml, который нужно применить (ему нужны строка таблицы и тд).Я также должен соответствующим образом открывать и закрывать таблицу перед первой дебетовой строкой и после последней кредитной строки.

Я был бы очень признателен за любую помощь, поскольку застрял даже при том, что простое приведенное выше выражение xpath работает правильно.

1 Ответ

3 голосов
/ 19 октября 2011

I. Решение XSLT 1.0 :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>
 <xsl:key name="kFollowing"
  match="*[not(self::static or self::header)]"
  use="generate-id(preceding-sibling::*
                              [self::static
                              or
                               self::header
                              ][1]
                  )"/>

 <xsl:template match="/*[static]">
  <p><xsl:value-of select="static"/></p>
  <ul>
    <xsl:apply-templates select="static|header"/>
  </ul>
 </xsl:template>

 <xsl:template match="static|header">
  <li>
    <xsl:value-of select=
     "concat(self::header, '&#xA;')"/>
    <table>
     <xsl:apply-templates
       select="key('kFollowing', generate-id())"/>
    </table>
  </li>
 </xsl:template>

 <xsl:template match=
  "*/*[not(self::static or self::header)]">
  <tr>
    <td>
     <xsl:value-of select=
      "translate(name(),'-', ' ')"/>
    </td>
  </tr>
 </xsl:template>
</xsl:stylesheet>

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

<question>
    <static><![CDATA[Static Data]]></static>
    <debit-row />
    <debit-row />
    <credit-row />
    <header><![CDATA[Header HTML 1]]></header>
    <debit-row />
    <debit-row />
    <credit-row />
</question>

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

<p>Static Data</p>
<ul>
   <li>

      <table>
         <tr>
            <td>debit row</td>
         </tr>
         <tr>
            <td>debit row</td>
         </tr>
         <tr>
            <td>credit row</td>
         </tr>
      </table>
   </li>
   <li>Header HTML 1
<table>
         <tr>
            <td>debit row</td>
         </tr>
         <tr>
            <td>debit row</td>
         </tr>
         <tr>
            <td>credit row</td>
         </tr>
      </table>
   </li>
</ul>

Объяснение : позиционная группировка с использованием ключа для определения всех элементов, принадлежащих группе.


II. Решение XSLT 2.0 :

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

 <xsl:template match="/*[static]">
  <p><xsl:value-of select="static"/></p>
  <ul>
    <xsl:for-each-group select="*"
         group-starting-with="static|header">
      <li>
        <xsl:value-of separator="&#xA;" select=
         "current-group()[1][self::header], ''"/>
        <table>
         <xsl:apply-templates
           select="current-group()[position() gt 1]"/>
        </table>
      </li>
    </xsl:for-each-group>
  </ul>
 </xsl:template>

 <xsl:template match=
  "*/*[not(self::static or self::header)]">
  <tr>
    <td>
     <xsl:value-of select=
      "translate(name(),'-', ' ')"/>
    </td>
  </tr>
 </xsl:template>
</xsl:stylesheet>

когда это преобразование XSLT 2.0 применяется к тому же XML-документу (см. Выше), снова получается тот же самый правильный результат <p>Static Data</p> <ul> <li> <table> <tr> <td>debit row</td> </tr> <tr> <td>debit row</td> </tr> <tr> <td>credit row</td> </tr> </table> </li> <li>Header HTML 1 <table> <tr> <td>debit row</td> </tr> <tr> <td>debit row</td> </tr> <tr> <td>credit row</td> </tr> </table> </li> </ul> Объяснение : Использование инструкции XSLT 2.0 <xsl:for-each-group> с атрибутом group-starting-with. Также используется стандартная функция XSLT 2.0 current-group().

...