在同一节点中查找previous-sibling和processing

时间:2013-07-16 12:37:17

标签: xslt xslt-2.0

需要使用XSLT将以下XML代码段转换为DITA。我的要求是: 1.所有标签都来自" orderedlist"应该包含在" context"节点。 2.所有标签都来自" orderedlist"应该在"结果"。 3.所有"包括"标签应该包含在它们之前的兄弟节点下。

XML:

        <?xml version="1.0" encoding="UTF-8"?>
        <procedure>
            <para>This is first para</para>
            <para>This is second para</para>
            <include>This is include</include>
            <orderedlist>
                <listitem>this is list item</listitem>
                <include>This is include</include>
                <listitem>this is list item <include>this is include</include></listitem>
            </orderedlist>
            <observation>this is observation</observation>
            <para>this is result para <include>this is include</include></para>
            <include>This is include</include>
        </procedure>

输出:

     <?xml version="1.0" encoding="UTF-8"?>
    <task>
        <context>
            <p>This is first para</p>
            <p>This is second para <included type='tag'>This is include</included>
            </p>
        </context>
        <ol>
            <li>this is list item <included type='tag'>This is include</included>
            </li>
            <li>this is list item <included type='tag'>this is include</included></li>
        </ol>
        <result>
            <observation>this is observation</observation>
            <p>this is result para <included type='tag'>this is include</included><included type='tag'>this is include</included>
            </p>
        </result>
    </task>

我的XSL:

        <?xml version="1.0" encoding="UTF-8"?>
        <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
            <xsl:template match="procedure">
                <task>
                    <context>
                        <xsl:apply-templates select="*[parent::procedure][following-sibling::orderedlist]"/>
                    </context>
                    <xsl:apply-templates select="orderedlist"/>
                    <result>
                        <xsl:apply-templates select="*[parent::procedure][preceding-sibling::orderedlist]"/>
                    </result>
                </task>
            </xsl:template>
            <xsl:template match="para">
                <p>
                    <xsl:apply-templates/>
                    <include>
                        <xsl:apply-templates select="following-sibling::include"/>
                    </include>
                </p>
            </xsl:template>
            <!-- rest of the template goes here   -->
            <xsl:template match="listitem">
                <li>
                    <xsl:apply-templates/>
                    <include>
                        <xsl:apply-templates select="following-sibling::include"/>
                    </include>
                </li>
            </xsl:template>
        </xsl:stylesheet>

任何指针都会有很大的帮助。感谢。

2 个答案:

答案 0 :(得分:2)

首先要注意的是,您可以简化以下表达式:

<xsl:apply-templates select="*[parent::procedure][following-sibling::orderedlist]"/>

此处不需要[parent::procedure],因为您已经定位在过程元素上,因此您知道如果选择任何子元素,它会将其作为父!

<xsl:apply-templates select="*[following-sibling::orderedlist]"/>

但是,您可能需要添加一个子句以确保此时不输出 include 元素,因为您需要使用特殊代码来处理它们以后再包含

<xsl:template match="include" />

要处理 include 元素,可能值得定义一个键,因此您可以通过第一个最多程序的非包含元素对它们进行分组,如此

  <xsl:key name="include" match="include" use="generate-id(preceding-sibling::*[not(self::include)][1])"/>

然后,在匹配 para listitem 等元素时,您可以获得要包含的 include 元素,如下所示:

<xsl:copy-of select="key('include', generate-id())"/>

注意我不确定如何处理单个元素的multipe include 元素,但在我的示例中,它将单独输出它们与合并它们相反:

这是完整的XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="xml" indent="yes"/>
  <xsl:key name="include" match="include" use="generate-id(preceding-sibling::*[not(self::include)][1])"/>

  <xsl:template match="procedure">
    <task>
      <context>
        <xsl:apply-templates select="*[following-sibling::orderedlist]"/>
      </context>
      <xsl:apply-templates select="orderedlist"/>
      <result>
        <xsl:apply-templates select="*[preceding-sibling::orderedlist]"/>
      </result>
    </task>
  </xsl:template>

  <xsl:template match="orderedlist">
    <ol>
      <xsl:apply-templates />
    </ol>
  </xsl:template>

  <xsl:template match="para">
    <p>
      <xsl:apply-templates/>
      <xsl:copy-of select="key('include', generate-id())" />
     </p>
  </xsl:template>

  <xsl:template match="listitem">
    <li>
      <xsl:apply-templates/>
      <xsl:copy-of select="key('include', generate-id())" />
    </li>
  </xsl:template>

  <xsl:template match="include" />

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

当应用于您的示例XML时,输出以下内容

<task>
  <context>
    <p>This is first para</p>
    <p>This is second para<include>This is include</include></p>
  </context>
  <ol>
    <li>this is list item<include>This is include</include></li>
    <li>this is list item</li>
  </ol>
  <result>
    <observation>this is observation</observation>
    <p>this is result para<include>This is include</include></p>
  </result>
</task>

答案 1 :(得分:1)

尝试一下:

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

  <xsl:template match="@* | node()" name="Copy">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()" />
      <xsl:call-template name="Include" />
    </xsl:copy>
  </xsl:template>
  <xsl:template match="procedure">
    <task>
      <context>
        <xsl:apply-templates select="*[following-sibling::orderedlist]"/>
      </context>
      <xsl:apply-templates select="orderedlist"/>
      <result>
        <xsl:apply-templates select="*[preceding-sibling::orderedlist]"/>
      </result>
    </task>
  </xsl:template>
  <xsl:template match="para">
    <p>
      <xsl:apply-templates/>
      <xsl:call-template name="Include" />
    </p>
  </xsl:template>
  <!-- rest of the template goes here   -->
  <xsl:template match="listitem">
    <li>
      <xsl:apply-templates/>
      <xsl:call-template name="Include" />
    </li>
  </xsl:template>

  <xsl:template name="Include">
    <xsl:apply-templates
      select="following-sibling::include[
                       generate-id(preceding-sibling::*[not(self::include)][1]) =
                       generate-id(current())]"
      mode="performIncludes"/>
  </xsl:template>

  <xsl:template match="include" />
  <xsl:template match="include" mode="performIncludes">
    <xsl:call-template name="Copy" />
  </xsl:template>
</xsl:stylesheet>

在样本输入上运行时的输出:

<task>
  <context>
    <p>This is first para</p>
    <p>This is second para<include>This is include</include></p>
  </context>
  <orderedlist>
    <li>this is list item<include>This is include</include></li>
    <li>this is list item</li>
  </orderedlist>
  <result>
    <observation>this is observation</observation>
    <p>this is result para<include>This is include</include></p>
  </result>
</task>