Проблема цикла XSL в XML - PullRequest
       1

Проблема цикла XSL в XML

2 голосов
/ 09 июня 2011

Мне нужно зациклить документ XML.Нет проблем.
Проблема возникает, когда мне нужен текст из предыдущей строки, которую я только что пропустил.

XML будет выглядеть примерно так

<lines>
  <line>
    <id>1</id>
    <text>Some fancy text here 1</text>
  </line>
  <line>
    <id></id>
    <text>This I need in the next line with a ID</text>
  </line>
  <line>
    <id></id>
    <text>Also need this.</text>
  </line>
  <line>
    <id>4</id>
    <text>Here we go</text>
  </line>
</lines>

Выходной файл XMLнужно выглядеть следующим образом

<output>
  <line>
    <id>1</id>
    <note>Some fancy text here 1</note>
  </line>
  <line>
    <id>4</id>
    <note>Here we go</note>
    <extra>
      <note>This I need in the next line with a ID</note>
      <note>Also need this.</note>
    </extra>
  </line>
</output>

У меня есть такой тариф XSL, так что просто разобраться в строке, для которой не установлен идентификатор.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <output>
    <xsl:for-each select="lines/line">
      <xsl:if test="id/text() &gt; 0">
        <line>
          <id>
            <xsl:value-of select="id" />
          </id>
          <note>
            <xsl:value-of select="text" />
          </note>
        </line>
      </xsl:if>
    </xsl:for-each>
    </output>
  </xsl:template>
</xsl:stylesheet>

Ответы [ 2 ]

2 голосов
/ 09 июня 2011

Вам необходимо выбрать предшествующего брата или сестру;здесь есть пример .

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

preceding-sibling::NodeName[1]
1 голос
/ 09 июня 2011

Я не удержался, чтобы полностью просмотреть ваш код:)

Здесь следует полное решение XSLT 1.0, более функционально ориентированное (без процедурного подхода). С первого взгляда это может показаться труднее увидеть, но, imho, это очень хороший пример для начала работы с механизмом шаблонов XSLT.

Также использовать xsl:for-each в вашем конкретном случае не так просто, потому что на определенном этапе цикла вы хотите получить все предшествующие соседние братья и сестры с пустым id, не зная, сколько их априори .

Я также использовал шаблон идентификации , чтобы упростить работу по воссозданию вашей цели.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:strip-space elements="*"/>

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

    <!-- match line with empty id and do not output -->
    <xsl:template match="line[not(boolean(id/text()))]"/>

    <!-- match line with id and build output -->
    <xsl:template match="line[boolean(id/text())]">
        <xsl:copy>
            <xsl:copy-of select="id"/>
            <xsl:apply-templates select="text"/>
            <extra>
                <!-- apply recursive template to the first preceding 
                sibling adajacent node with empty id -->
                <xsl:apply-templates select="(preceding-sibling::*[1])
                    [name()='line' and not(boolean(id/text()))]/text" 
                    mode="extra"/>
            </extra>
        </xsl:copy>
    </xsl:template>

    <!-- change text element to note --> 
    <xsl:template match="text">
        <note>
            <xsl:value-of select="."/>
        </note>
    </xsl:template>

    <!-- recursive template for extra note elements -->
    <xsl:template match="text" mode="extra">
        <note>
            <xsl:value-of select="."/>
        </note>
        <xsl:apply-templates select="(parent::line/preceding-sibling::*[1])
            [name()='line' and not(boolean(id/text()))]/text" 
            mode="extra"/>
    </xsl:template>

</xsl:stylesheet>

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

<?xml version="1.0" encoding="UTF-8"?>
<lines>
   <line>
      <id>1</id>
      <note>Some fancy text here 1</note>
      <extra/>
   </line>
   <line>
      <id>4</id>
      <note>Here we go</note>
      <extra>
         <note>Also need this.</note>
         <note>This I need in the next line with a ID</note>
      </extra>
   </line>
</lines>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...