如何使用XSLT将所有这些XML标签连接成同名的较大标签?

问题描述:


我这个转换XML:
如何使用XSLT将所有这些XML标签连接成同名的较大标签?

<root> 
    <contrib contrib-type="author"> 
    <name> 
     <last-name>Kottke</last-name> 
     <first-name>Leo</first-name> 
    </name> 
    </contrib> 

    <contrib contrib-type="author"> 
    <name> 
     <last-name>McKee</last-name> 
     <first-name>Andy</first-name> 
    </name> 
    </contrib> 

    <contrib contrib-type="author"> 
    <name> 
     <last-name>Hedges</last-name> 
     <first-name>Michael</first-name> 
    </name> 
    </contrib> 
</root> 

...这个XSL:

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

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

     <!-- Authors --> 
     <xsl:template match="contrib[@contrib-type='author']"> 
      <Authors> 
       <xsl:if test="position() != last()"> 
       <xsl:value-of select = "concat(name/first-name, ' ', name/last-name, ', ')" /> 
       </xsl:if> 

       <xsl:if test="position() = last()"> 
       <xsl:value-of select = "concat('and ', name/first-name, ' ', name/last-name, '.')" /> 
       </xsl:if> 
      </Authors> 
     </xsl:template> 
</xsl:stylesheet> 

...并正在此输出:

<root> 
    <Authors>Leo Kottke, </Authors> 
    <Authors>Andy McKee, </Authors> 
    <Authors>and Michael Hedges.</Authors> 
</root> 





然而,我想所有的  Author  标签连接成一个更大的  Author  标签,使输出将类似于此

<root> 
    <Authors>Leo Kottke, Andy McKee, and Michael Hedges.</Authors> 
</root> 


待办事项我需要以某种方式使用  for-each  循环?

xsl:for-each需要。只需从contrib比赛添加模板/*(或/root)和删除Authors

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

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

    <xsl:template match="/root"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*"/> 
      <Authors> 
       <xsl:apply-templates select="contrib[@contrib-type='author']"/> 
      </Authors> 
     </xsl:copy> 
    </xsl:template> 

    <!-- Authors --> 
    <xsl:template match="contrib[@contrib-type='author']"> 
     <xsl:if test="position() != last()"> 
      <xsl:value-of select = "concat(name/first-name, ' ', name/last-name, ', ')" /> 
     </xsl:if> 

     <xsl:if test="position() = last()"> 
      <xsl:value-of select = "concat('and ', name/first-name, ' ', name/last-name, '.')" /> 
     </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 
+0

感谢@DevNull的帮助!然而,除了'Authors'之外,我还有许多其他这样的标签进行转换,并且将这些代码附加到其余的部分是相冲突的,并且导致* only *'Authors'输出... – 2012-08-08 20:07:12

+0

啊,所以我改变了''到'',现在它工作正常。我并不确定我在那里弄清楚了什么,但是似乎将Authors转换应用于所有属性会使所有不符合条件的节点都为零。再次感谢@DevNull! – 2012-08-08 20:28:04

+0

很好的答案,+1。 – ABach 2012-08-09 00:32:16

简单的东西一点点

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0"> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="/root"> 
     <xsl:variable name="authors"> 
      <xsl:for-each select="contrib/name"> 
       <xsl:text>, </xsl:text> 
       <xsl:value-of select="first-name"/> 
       <xsl:text> </xsl:text> 
       <xsl:value-of select="last-name"/> 
      </xsl:for-each> 
     </xsl:variable> 

     <root> 
      <authors><xsl:value-of select="substring($authors,3)"/></authors> 
     </root> 
    </xsl:template> 

</xsl:stylesheet> 
+0

感谢@Jim的帮助!然而,名字的数量是未知的大小(不总是只有3),并且''元素的位置将根据根的不同而变化... – 2012-08-08 20:10:57

+1

我的答案限制3次发生。至于变化的深度,只需将选择改为'.// contrib/name'。 – 2012-08-08 20:28:27

+0

对不起,我误解了' 2012-08-08 20:44:37