0

Need to transform following XML snippet into DITA using XSLT. My requirements are: 1. All the tags comes before "orderedlist" should be wrapped under "context" node. 2. All the tags comes after "orderedlist" should be in "result". 3. All the "include" tags should be wrapped under their preceding sibling nodes.

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>

Output:

     <?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>

My 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>

Any pointer will be a great help. Thanks.

4

2 回答 2

2

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

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

你不需要[parent::procedure]这里,因为你已经定位在一个过程元素上,所以你知道如果你选择任何子元素,它将把它作为父元素!

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

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

<xsl:template match="include" />

要处理包含元素,可能值得定义一个键,因此您可以按第一个最重要的非包含元素对它们进行分组,如下所示

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

然后,当匹配诸如paralistitem之类的元素时,您可以获取要包含的包含元素,就像这样:

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

请注意,我不确定您要如何处理单个元素的多重包含元素,但在我的示例中,它将分别输出它们以反对合并它们:

这是完整的 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>
于 2013-07-16T13:08:56.250 回答
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>
于 2013-07-16T13:09:50.970 回答