2017-05-26 69 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元件,
  • “重放” 的源元件 (环路的当前元素)的内部。