2011-02-26 310 views
5

我想根据派生元素的位置拆分元素树。 (特别是,我试图解析Adobe的IDML)。我希望能够在树上,看起来像转换:XSLT在后代节点处拆分树

<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/>标签,但它们是否存在并不重要,因为它们所包含的信息现在由拆分元素表示,我认为解决此问题可能更容易无需担心他们留在)

我试着用xsl:for-each-group作为XSLT 2.0规范建议(例如<xsl:for-each-group select="CharacterStyleRange/*" group-ending-with="Br">),但我无法弄清楚如何应用在树的每一级(<Br />标签可以出现在任何级别,如A <CharacterStyleRange>元素的内部<Hyperlink>元素中,这也限制了我适用于选定的深度只能有模板

编辑:我的例子鳕鱼e只显示了树需要分割的一个地方,但是可以有任意数量的分割点(总是相同的元素,尽管如此)。

编辑2:我已经添加了一些更详细的示例,以显示一些并发症。

+1

好问题,+1。查看我的回答,获取完整,简短和简单的解决方案。 :) – 2011-02-27 02:43:44

+0

+1好问题。 :-) – LarsH 2011-02-27 03:03:31

+0

这很难找到,但这里是重复的http://stackoverflow.com/questions/3863274/move-separator-elements-upwards-in-xml-hierarchy – 2011-02-28 16:34:44

回答

6

这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> 
+0

嗯,似乎这只能让你拆分树在一个地方。我想我的问题并不清楚,可能有多个'
'元素,每个元素都需要分割树。 – 2011-02-27 05:45:37

+0

@Quentin Smith:那么你必须编辑你的问题,并提供一个更具代表性的例子。 – 2011-02-27 05:56:09

+0

@Dimitre Novatchev:谢谢你的建议。我试图保持简单的例子,但我想这太简单了,不能真正说明问题。我已经编辑了这个问题来有一个更大的例子。 – 2011-02-27 06:20:07