2017-05-26 88 views
1

這裏是XML:XSLT如何通過每個節點的循環,敷在標籤

<svg xmlns:xlink="http://www.w3.org/1999/xlink"> 
    <g> 
     <text id="b376"> 
      <tspan x="59" y="156" font-size="13px" font-family="Arial">80</tspan> 
     </text> 
     <use xlink:href="#b376" fill="#000000"/> 
     <text id="b374"> 
      <tspan x="59" y="204" font-size="13px" font-family="Arial">60</tspan> 
     </text> 
     <use xlink:href="#b374" fill="#000000"/> 
     <defs>testDef</defs> 
    </g> 
</svg> 

這裏是我的XSL輸入:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 
    <xsl:template match="node()|@*"> 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
    </xsl:template> 
    <xsl:template match="g"> 
    <g> 
     <xsl:apply-templates select="use|defs"/> 
     <defs> 
     <xsl:apply-templates select="*[name() != 'use' and name() != 'defs']"/> 
     </defs> 
    </g> 
    </xsl:template> 
</xsl:stylesheet> 

我想包裝的所有節點在DEFS標籤除了使用標籤和defs標籤外。所以2個文本節點將被包裹在defs標籤中,但是defs和use不會。

這裏是我得到

<?xml version="1.0"?> 
<svg xmlns:xlink="http://www.w3.org/1999/xlink"> 
    <g> 
    <use xlink:href="#b376" fill="#000000"/> 
    <use xlink:href="#b374" fill="#000000"/> 
    <defs>testDef</defs> 
    <defs> 
     <text id="b376"> 
     <tspan x="59" y="156" font-size="13px" font-family="Arial">80</tspan> 
     </text> 
     <text id="b374"> 
     <tspan x="59" y="204" font-size="13px" font-family="Arial">60</tspan> 
     </text> 
    </defs> 
    </g> 
</svg> 

這就是我想要的東西:

<?xml version="1.0"?> 
    <svg xmlns:xlink="http://www.w3.org/1999/xlink"> 
     <g> 
     <use xlink:href="#b376" fill="#000000"/> 
     <use xlink:href="#b374" fill="#000000"/> 
     <defs>testDef</defs> 
     <defs> 
      <text id="b376"> 
      <tspan x="59" y="156" font-size="13px" font-family="Arial">80</tspan> 
      </text> 
     </defs> 
     <defs> 
      <text id="b374"> 
      <tspan x="59" y="204" font-size="13px" font-family="Arial">60</tspan> 
      </text> 
     </defs> 
     </g> 
    </svg> 

我使用this在線工具測試。謝謝!

回答

1

您當前的輸出,其中所有的<text>元素都包裹在一個<defs>標籤,這正是我會閱讀您的XSL代碼期望 - 爲每個<g>,你有一個<defs>在其中你處理所有的元素不屬於<use><defs>

<xsl:template match="g"> 
    <g> 
     <xsl:apply-templates select="use|defs"/> 

     <!-- This part here: --> 
     <defs> 
      <xsl:apply-templates select="*[name() != 'use' and name() != 'defs']"/> 
     </defs> 

    </g> 
</xsl:template> 

由於<xsl:apply-templates select="*[name() != 'use' and name() != 'defs']"/>內部字面<defs>所有的非use和非refs元素作爲批處理,在該單個文字元素內處理。

你顯然希望每個非use和非defs元素包裝在它自己的<defs>。在這種情況下,您需要將文字<defs>移動到內的一個單獨的模板,該模板與非use和非defs元素匹配。

快速和骯髒的重構可能是這樣的:

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

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

    <!-- We don't really need a specific template for <g>, so 
     we let the identity template handle that case. --> 

    <!-- The only case where we need to define a different flow is 
     for children of <g> elements, that aren't <use> or <defs>. --> 
    <xsl:template match="*[name(..) = 'g'][name() != 'use' and name() != 'defs']"> 
     <!-- The template matches _each_ such element, so if we 
      put the literal `<defs>` here, we get that `<defs>` as 
      a wrapper for _each_ such element. --> 
     <defs> 
      <xsl:copy-of select="."/> 
     </defs> 
    </xsl:template> 

</xsl:stylesheet> 

注意,這種方法也使在同一位置<g>父母中的原始<use><defs>元素。

+0

'[name(..)='g']'謂詞有點奇怪。以'g/*'開頭的位置路徑會更簡單和更自然。另外,我不考慮'[name()!= ...]'謂詞,我會考慮* no *謂詞,而是使用匹配'g/use | g/defs'的模板來替代。 –

+0

你已經使用過'xsl:copy-of',你似乎指'xsl:copy'包含'xsl:apply-templates'。 –

+1

我不同意'[name(..)='g']'謂詞很奇怪。 相反,它以相當自然的方式讀取: *父元素的名稱是'g'*。 另一種可能性是'[parent :: g和...]' - 都在** one **謂詞中。 –

1

您的預期輸出顯示元素 的順序對您很重要。

你想第一usedefs標籤,只有後他們 所有剩餘的元素,每個包裹在自己的defs 元素。

爲了實現這個使用下面的腳本:

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

    <xsl:template match="g"> 
    <g> 
     <xsl:apply-templates select="use|defs"/> 
     <xsl:for-each select="*[name() != 'use' and name() != 'defs']"> 
     <defs> 
      <xsl:apply-templates select="."/> 
     </defs> 
     </xsl:for-each> 
    </g> 
    </xsl:template> 

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

正如你看到的,我加了一個for-each循環從你的例子複製的select 屬性。

該環路中的含量:

  • 創建包裝defs元件,
  • 「重放」 的源元件 (環路的當前元素)的內部。