XSLT 在后代节点拆分树 [英] XSLT split a tree at a descendent node

查看:20
本文介绍了XSLT 在后代节点拆分树的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试根据后代元素的位置拆分元素树.(特别是,我正在尝试解析 Adob​​e 的 IDML.)我希望能够转换如下所示的树:

I'm trying to split a tree of elements based on the location of a descendent element. (In particular, I'm trying to parse Adobe's IDML.) I'd like to be able to convert a tree that looks like:

<ParagraphStyleRange style="foo">
 <CharacterStyleRange style="bar">
  <Content>foo</Content>
  <Br />
  <Content>bar</Content>
 </CharacterStyleRange>
 <CharacterStyleRange style="bop">
  <Content>baz</Content>
  <Br />
  <Hyperlink>
   <Content>boo</Content>
    <Br />
   <Content>meep</Content>
  </Hyperlink>
</ParagraphStyleRange>

分裂成树:

<ParagraphStyleRange style="foo">
 <CharacterStyleRange style="bar">
  <Content>foo</Content>
 </CharacterStyleRange>
</ParagraphStyleRange>

<ParagraphStyleRange style="foo">
 <CharacterStyleRange style="bar">
  <Content>bar</Content>
 </CharacterStyleRange>
 <CharacterStyleRange style="bop">
  <Content>baz</Content>
 </CharacterStyleRange>
</ParagraphStyleRange>

<ParagraphStyleRange style="foo">
 <CharacterStyleRange style="bop">
  <Hyperlink>
   <Content>boo</Content>
  </Hyperlink>
 </CharacterStyleRange>
</ParagraphStyleRange>

<ParagraphStyleRange style="foo">
 <CharacterStyleRange style="bop">
  <Hyperlink>
   <Content>meep</Content>
  </Hyperlink>
 </CharacterStyleRange>
</ParagraphStyleRange>

然后我可以使用普通的 XSL 解析它.(我最初在其原始位置显示了 <Br/> 标签,但它们是否在那里并不重要,因为它们包含的信息现在由拆分元素.我认为解决这个问题可能更容易,而不必担心保留它们.)

which I can then parse using normal XSL. ( I originally showed the <Br/> tags in their original place, but it doesn't really matter if they are there or not, since the information they contained is now represented by the split elements. I think it's probably easier to solve this problem without worrying about keeping them in.)

我尝试按照 XSLT 2.0 规范中的建议使用 xsl:for-each-group(例如 <xsl:for-each-group select="CharacterStyleRange/*" group-Ending-with="Br">),但我不知道如何在树的每一层应用它(<Br/> 标签可以出现在任何级别,例如在 元素内的 元素内,它也限制我只能拥有适用于所选深度的模板.

I tried using xsl:for-each-group as suggested in the XSLT 2.0 spec (e.g. <xsl:for-each-group select="CharacterStyleRange/*" group-ending-with="Br">), but I can't figure out how to apply that at every level of the tree (<Br /> tags can appear at any level, e.g. inside a <Hyperlink> element inside of a <CharacterStyleRange> element, and it also limits me to only having templates that apply at the chosen depth.

我的示例代码只显示了一个需要拆分树的地方,但可以有任意数量的拆分点(尽管总是相同的元素.)

My example code shows only one place where the tree needs to be split, but there can be any number of split points (always the same element, though.)

编辑 2:我添加了一些更详细的示例,以显示一些复杂情况.

EDIT 2: I've added some a more detailed example, to show some of complications.

推荐答案

这个 XSLT 1.0(当然还有 XSLT 2.0)转换:

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

       <xsl:template match="text()"/>

       <xsl:template match="/">
         <xsl:call-template name="Split">
          <xsl:with-param name="pSplitters"
           select="//Br"/>
         </xsl:call-template>
       </xsl:template>

       <xsl:template name="Split">
         <xsl:param name="pSplitters"/>

         <xsl:if test="$pSplitters">
           <xsl:for-each select="$pSplitters[1]">

             <xsl:call-template name="buildTree">
              <xsl:with-param name="pLeafs" select=
              "preceding-sibling::node()[not(descendant::Br)]"/>
          </xsl:call-template>

          <xsl:if test=
            "not(following-sibling::node()//Br)">
                 <xsl:call-template name="buildTree">
                  <xsl:with-param name="pLeafs" select=
                  "following-sibling::node()"/>
                 </xsl:call-template>
          </xsl:if>

          <xsl:call-template name="Split">
            <xsl:with-param name="pSplitters" select=
             "$pSplitters[position() > 1]"/>
          </xsl:call-template>
          </xsl:for-each>
         </xsl:if>
       </xsl:template>

 <xsl:template name="buildTree">
  <xsl:param name="pAncestors" select="ancestor::*"/>
  <xsl:param name="pLeafs"/>

  <xsl:choose>
    <xsl:when test="not($pAncestors)">
     <xsl:copy-of select="$pLeafs"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="vtopAncestor" select="$pAncestors[1]"/>

      <xsl:element name="{name($vtopAncestor)}"
           namespace="{namespace-uri($vtopAncestor)}">
        <xsl:copy-of select=
             "$vtopAncestor/namespace::* | $vtopAncestor/@*"/>
        <xsl:call-template name="buildTree">
          <xsl:with-param name="pAncestors"
               select="$pAncestors[position()>1]"/>
          <xsl:with-param name="pLeafs" select="$pLeafs"/>
        </xsl:call-template>
      </xsl:element>
     </xsl:otherwise>
  </xsl:choose>
 </xsl:template>
</xsl:stylesheet>

应用于提供的 XML 文档时:

<ParagraphStyleRange style="foo">
    <CharacterStyleRange style="bar">
        <Content>foo</Content>
        <Br />
        <Content>bar</Content>
    </CharacterStyleRange>
    <CharacterStyleRange style="bop">
        <Content>baz</Content>
        <Br />
        <Hyperlink>
            <Content>boo</Content>
            <Br />
            <Content>meep</Content>
        </Hyperlink>
    </CharacterStyleRange>
</ParagraphStyleRange>

产生想要的、正确的结果:

<ParagraphStyleRange style="foo">
   <CharacterStyleRange style="bar">
      <Content>foo</Content>
   </CharacterStyleRange>
</ParagraphStyleRange>
<ParagraphStyleRange style="foo">
   <CharacterStyleRange style="bar">
      <Content>bar</Content>
   </CharacterStyleRange>
</ParagraphStyleRange>
<ParagraphStyleRange style="foo">
   <CharacterStyleRange style="bop">
      <Content>baz</Content>
   </CharacterStyleRange>
</ParagraphStyleRange>
<ParagraphStyleRange style="foo">
   <CharacterStyleRange style="bop">
      <Hyperlink>
         <Content>boo</Content>
      </Hyperlink>
   </CharacterStyleRange>
</ParagraphStyleRange>
<ParagraphStyleRange style="foo">
   <CharacterStyleRange style="bop">
      <Hyperlink>
         <Content>meep</Content>
      </Hyperlink>
   </CharacterStyleRange>
</ParagraphStyleRange>

这篇关于XSLT 在后代节点拆分树的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆