使用xslt为具有相同名称的多个元素刷新位置

时间:2016-11-23 10:24:36

标签: xml xslt xslt-1.0 xslt-2.0

源xml文档:

<item>
 <p languageCode="en">en</p>
 <p languageCode="fr">fr</p>
 <c languageCode="de">de</c>
 <c languageCode="nl">nl</c>
</item>

转换所需的结果必须是这个xml文档:

<item>
 <p pos="1">en</p>
 <p pos="2">fr</p>
 <c pos="1">de</c>
 <c pos="2">nl</c>
</item>

使用xslt是否可以实现呢?

2 个答案:

答案 0 :(得分:2)

在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:template match="/item">
    <xsl:copy>
        <xsl:for-each-group select="*" group-adjacent="name()"> 
            <xsl:apply-templates select="current-group()"/> 
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>

<xsl:template match="p | c">
    <xsl:copy>
        <xsl:attribute name="pos" select="position()"/>
        <xsl:value-of select="."/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

答案 1 :(得分:1)

XSLT 1.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="/*">
   <item><xsl:apply-templates/></item>
 </xsl:template>


     <xsl:template match="/*/*">
      <xsl:copy>
         <xsl:attribute name="pos">
           <xsl:value-of select="count(preceding-sibling::*[name()=name(current())])+1"/>
         </xsl:attribute>
         <xsl:apply-templates/>
       </xsl:copy>
     </xsl:template>
    </xsl:stylesheet>

XSLT 2.0

<xsl:stylesheet version="2.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="/*">
   <item><xsl:apply-templates/></item>
 </xsl:template>

 <xsl:template match="/*/*">
  <xsl:copy>
     <xsl:attribute name="pos" 
                    select="count(preceding-sibling::*[name()=name(current())])+1"/>
     <xsl:apply-templates/>
   </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

另一个XSLT 2.0解决方案

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:key name="kByName" match="/*/*" use="name()"/>

 <xsl:template match="/*">
   <item><xsl:apply-templates/></item>
 </xsl:template>

 <xsl:template match="/*/*">
  <xsl:copy>
     <xsl:attribute name="pos" 
                  select="index-of(key('kByName', name())/generate-id(), generate-id())"/>
     <xsl:apply-templates/>
   </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档

<item>
    <p languageCode="en">en</p>
    <p languageCode="fr">fr</p>
    <c languageCode="de">de</c>
    <c languageCode="nl">nl</c>
</item>

所有三个解决方案都会产生所需的正确结果:

<item>
   <p pos="1">en</p>
   <p pos="2">fr</p>
   <c pos="1">de</c>
   <c pos="2">nl</c>
</item>

请注意

所有这些解决方案都是泛型 - 它们不依赖于名称,数量,名称数量或元素顺序。

例如,应用于以下XML文档时:

<item>
    <p languageCode="en">en</p>
    <p languageCode="fr">fr</p>
    <c languageCode="de">de</c>
    <c languageCode="nl">nl</c>
    <d languageCode="es">es</d>
    <d languageCode="bg">bg</d>
    <d languageCode="pl">pl</d>
</item>

所有三种解决方案都能产生所需的正确结果

<item>
   <p pos="1">en</p>
   <p pos="2">fr</p>
   <c pos="1">de</c>
   <c pos="2">nl</c>
   <d pos="1">es</d>
   <d pos="2">bg</d>
   <d pos="3">pl</d>
</item>