xml - XSLT将线性结构转换为非线性

标签 xml xslt xpath xslt-1.0

我和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/

相关文章:

java - 非法注释异常 : Class has two properties of same name

xml - 在输出地址节点之前检查 5 行中至少有 2 行存在于 XSL 1.0 中的地址上

xslt - XSLT 中的位置字符串拆分

javascript - CasperJS 中的 CSS 和 XPath 选择器

xslt - 如果 parent 没有匹配的 child ,则选择XSLT选择节点

java - 无法解析具有不同命名空间的 XML

c# - 如何从流中将新元素附加到 Xml

iphone - 在手机之间发送 NSDictionary

xml - 选择包含 "foo"的属性的正确 XPath 是什么?

c# - XSLT 的输出参数