2011-02-26 53 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