【问题标题】:finding preceding-sibling and processing in same node在同一节点中查找前同级和处理
【发布时间】:2013-07-16 12:37:16
【问题描述】:

需要使用 XSLT 将 XML sn-p 转换为 DITA。我的要求是: 1.所有标签都在“orderedlist”之前应该被包裹在“context”节点下。 2.“orderedlist”之后的所有标签都应该在“result”中。 3.所有的“include”标签都应该被包裹在它们前面的兄弟节点之下。

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>

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

【问题讨论】:

    标签: xslt xslt-2.0


    【解决方案1】:

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

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

    这里你不需要[parent::procedure],因为你已经定位在一个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])"/>
    

    然后,当匹配 paralistitem 等元素时,就可以得到 include 元素来包含,就像这样:

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

    请注意,我不确定您要如何处理单个元素的多个 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. 'inlcude' 标签可以出现在 xml 中的任何地方,我必须按原样处理它(前面的兄弟逻辑不应该适用于那些 'include')。 2. 我可能不得不操作“包含”标签,因此,我必须使用应用模板而不是复制。任何建议都会有很大帮助。
    【解决方案2】:

    试试这个:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-06-22
      • 1970-01-01
      • 2011-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-25
      • 1970-01-01
      相关资源
      最近更新 更多