我和XML

<main>
    <div type='scene'>
        <l>l1</l>
        <sp>A speach</sp>
        <l>l2</l>
        <pb />
        <l>l3</l>
       <l>14</l>
    </div>
</main>


我的任务是将其转换为

<div class="line-group">
    <l>l1</l>
    <div class="speach">
       A speach
    </div>
    <l>l2</l>
</div>
<div class="line-group">
    <l>l3</l>
    <l>l4</l>
</div>


我知道<pb />可能有任意数量,并且只有在没有连续的<pb />并且开始和结束时都没有<pb />的情况下,才能正确实现此输出。

但是,我们可以使用这种方法将所有<pb />替换为</div><div class="line-group">,并在开头添加一个<div class="line-group">,在结尾添加一个</div>

如何在XSLT中做到这一点?

我具有所有其他标签的模板,在示例中使用sp表示<l>不是唯一的子项。

最佳答案

您可以定义一个键,以根据每个场景中最近的pb元素将每个场景中的非pb元素收集到组中。

<xsl:key name="elByPb" match="*[not(self::pb)]"
                       use="concat(generate-id(..), '|',
                                   generate-id(preceding-sibling::pb[1]))" />


现在要处理场景,请为第一个line-group之前的元素创建一个pb,然后为每个pb之后的元素创建另一个:

<xsl:template match="div[@type='scene']">
  <xsl:copy>
    <xsl:copy-of select="@*" />
    <xsl:call-template name="line-group">
      <xsl:with-param name="groupKey" select="concat(generate-id(), '|')" />
    </xsl:call-template>
    <xsl:apply-templates select="pb" />
  </xsl:copy>
</xsl:template>

<xsl:template match="pb" name="line-group">
  <xsl:param name="groupKey"
             select="concat(generate-id(..), '|', generate-id())" />
  <div class="line-group">
    <xsl:apply-templates select="key('elByPb', $groupKey)" />
  </div>
</xsl:template>


在这里,我利用了一个事实,即空节点集的generate-id(根据定义)是空字符串,因此,节中第一个pb之前的元素将被键入"id-of-parent|"

关于xml - XSLT将线性结构转换为非线性,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24127128/

10-12 05:48