2017-08-08 77 views
3

假設有與內容模型中的元件如下:當兄弟元素任意存在時,XSLT按順序創建元素?

<!ELEMENT wrapper (a*,b*,c*,d*,e*,f*,g*,h*,i*,j*,k*,l*,m*,n*,o*,p*,q*,r*,s*,t*,u*,v*,w*,x*,y*,z*)> 

換言之,一個包裝元件內有可能存在任意子元素的指定順序。

您需要在包裝中創建一個新元素(例如m),同時保留已經存在的元素並確保輸出符合內容模型。

這是排序的溶液:

<xsl:template match="@*|node()"> 
    <xsl:sequence select="."/> 
</xsl:template> 

<xsl:template match="wrapper"> 
    <xsl:copy> 
    <xsl:apply-templates select="a,b,c,d,e,f,g,h,i,j,k,l,m"/> 
    <m>This is new</m> 
    <xsl:apply-templates select="n,o,p,q,r,s,t,u,v,w,x,y,z"/> 
    </xsl:copy> 
</xsl:template> 

然而,這種方案將降低包裝元素之內的所有的空格,註釋或處理指令。我已經想出了一些解決方案,不會丟棄那些東西,但沒有任何我很滿意的解決方案。

什麼是這個問題最優雅的解決方案,不會丟棄節點? XSLT 3和架構感知解決方案都很好。

下面是一些例子輸入和輸出:

<!-- Input --> 
<wrapper/> 

<!-- Output --> 
<wrapper><m>This is new</m></wrapper> 

<!-- Input --> 
<wrapper><a/><z/></wrapper> 

<!-- Output --> 
<wrapper><a/><m>This is new</m><z/></wrapper> 

<!-- Input --> 
<wrapper><m/></wrapper> 

<!-- Output --> 
<wrapper><m/><m>This is new</m></wrapper> 

<!-- Input --> 
<wrapper> 
    <a/> 
    <!-- put m here --> 
    <z/> 
</wrapper> 

<!-- Output --> 
<!-- NB: The comment and whitespace could come after the inserted element instead. This case is ambiguous --> 
<wrapper> 
    <a/> 
    <!-- put m here --><m>This is new</m> 
    <z/> 
</wrapper> 

<!-- Input --> 
<wrapper> 
    <a/> 
    <b/> 
    <c/> 
    <n/> 
    <o/> 
    <!-- p is not here --> 
    <?do not drop this?> 
</wrapper> 

<!-- Output --> 
<wrapper> 
    <a/> 
    <b/> 
    <c/><m>This is new</m> 
    <n/> 
    <o/> 
    <!-- p is not here --> 
    <?do not drop this?> 
</wrapper> 

這不是關鍵的是插入的元素周圍非元素節點之前或之後來到,只是他們沒有丟棄,它們相對於順序原始元素被保留。

+0

您可以指示模板/秒匹配子元素以複製任何尾隨(或領先)文本,註釋或處理指令點頭ES。 - P.S.這[mcve]可能會有用。 –

+2

@Danielhaley'm'可能不存在,因爲我理解 –

回答

5

這裏你可以看看它的一種方法:

XSLT 2.0

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

<!-- identity transform --> 
<xsl:template match="@*|node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="wrapper"> 
    <xsl:variable name="all" select="node()"/> 
    <xsl:variable name="middle" select="(n,o,p,q,r,s,t,u,v,w,x,y,z)[1]"/> 
    <xsl:variable name="i" select="if($middle) then count($all[. &lt;&lt; $middle]) else count($all)"/> 
    <xsl:variable name="new"> 
     <m>This is new</m> 
    </xsl:variable> 
    <xsl:copy> 
     <xsl:apply-templates select="insert-before($all, $i+1, $new) "/> 
    </xsl:copy> 
</xsl:template> 

</xsl:stylesheet> 

或者,如果你喜歡:

<xsl:template match="wrapper"> 
    <xsl:variable name="all" select="node()"/> 
    <xsl:variable name="middle" select="(a,b,c,d,e,f,g,h,i,j,k,l,m)[last()]"/> 
    <xsl:variable name="i" select="if($middle) then index-of($all/generate-id(), generate-id($middle)) else 0"/> 
    <xsl:variable name="new"> 
     <m>This is new</m> 
    </xsl:variable> 
    <xsl:copy> 
     <xsl:apply-templates select="insert-before($all, $i+1, $new) "/> 
    </xsl:copy> 
</xsl:template>