简体   繁体   English

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

[英]refresh position using xslt for multiple elements with same name

The source xml document: 源xml文档:

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

The needed result of the transformation must be this xml document: 转换所需的结果必须是以下xml文档:

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

using xslt is it possible achieve it? 使用xslt是否有可能实现?

In XSLT 2.0 you can do: 在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>

XSLT 1.0: 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 : 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>

Another XSLT 2.0 solution : 另一个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>

When applied on the provided XML document : 当应用于提供的XML文档时

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

All three solutions produce the wanted, correct result: 这三种解决方案都能产生想要的正确结果:

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

Do note : 注意事项

All these solutions are generic -- they don't depend on the names, number, number of names or order of elements. 所有这些解决方案都是通用的 -它们不依赖于名称,数量,名称数量或元素顺序。

For example, when applied on the following XML document: 例如,当应用于以下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>

all three solutions produce the wanted, correct result : 这三种解决方案都能产生想要的正确结果

<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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM