Xml XSLT1将非唯一元素转换为网格的属性

Xml XSLT1将非唯一元素转换为网格的属性,xml,xslt,xslt-1.0,xslt-grouping,Xml,Xslt,Xslt 1.0,Xslt Grouping,我有一个具有这种结构的XML文件 99 2. 4. 1. 6. 1. 2. 5. 3. 回答一个试图回答问题却没有付出任何努力的问题不是一个好主意。。。 但是,不管怎样,它在这里 XSL 1.0: , 给予: 例子: 参考资料: 以下是一种非常有效的方法: <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xm

我有一个具有这种结构的XML文件


99
2.
4.
1.
6.
1.
2.
5.
3.

回答一个试图回答问题却没有付出任何努力的问题不是一个好主意。。。 但是,不管怎样,它在这里

XSL 1.0:

,
给予:

例子:

参考资料:

  • 以下是一种非常有效的方法:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
    
      <xsl:key name="kDistinctChildren" match="level/*"
               use="concat(generate-id(..), '+', name())" />
    
      <xsl:template match="@* | node()">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()" />
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="level">
        <xsl:copy>
          <xsl:apply-templates select="@*" />
          <xsl:apply-templates mode="group"
                 select="*[generate-id() = 
                           generate-id(key('kDistinctChildren',
                                       concat(generate-id(..), '+', name()))[1])]" />
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="*" mode="group">
        <xsl:attribute name="{name()}">
          <xsl:apply-templates select="key('kDistinctChildren', 
                                         concat(generate-id(..), '+', name()))" 
                               mode="joinWithCommas"/>
        </xsl:attribute>
      </xsl:template>
    
      <xsl:template match="*" mode="joinWithCommas">
        <xsl:value-of select="concat(., substring(',', 1, position() != last()))"/>
      </xsl:template>
    
    </xsl:stylesheet>
    
    
    
    在示例输入上运行时,输出为:

    <levels>
      <level id="0" qd="NE" gate="99" zone="2" laydown="4" />
      <level id="0" qd="SE" gate="1" zone="6,5" laydown="1,2,3" />
    </levels>
    
    
    
    是否已知和详尽的
    id
    qd
    gate
    zone
    堆放?或者您需要从源XML动态获取属性列表吗?您已经尝试了什么?好的,这会起作用-但是这是一个好的解决方案吗?基本上,覆盖同一属性的次数与覆盖同名节点的次数相同。这样浪费CPU的能量会让大脑产生反抗……对于以下输入,这将无法正常工作:
    99 2 4 99 2 4
    。谢谢@JLRishe,很好的回答!我又回到了我以前的版本(不管怎样效果更好)。我确实花了一些时间在这方面做了努力,但作为一个新手,我觉得这是一个垃圾,所以没有看到把它包括进去的意义。我愚蠢地认为XML很简单,所以我想我会使用它,但最终花费的时间是DB解决方案的3到4倍。至于xslt代码的正确性。。。。。我已经尝试了上述方法,除了VS2013崩溃和重新启动之外,我还遇到了一个错误“此文档已经有一个“文档元素节点”。@nickhoore不是问题,Nick,XSLT不是一个容易驯服的野兽!永远不要忽视自己编写代码的尝试,我更愿意帮助别人编写自己的代码,而不仅仅是给他们答案。祝你好运一个非常好的解决方案@NickHoare—这是一个很好的例子,说明使用XSLT 2.0()执行某些任务是多么容易。@NickHoare如果您回答了澄清请求,可能会找到一个更简单的答案。
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
    
      <xsl:key name="kDistinctChildren" match="level/*"
               use="concat(generate-id(..), '+', name())" />
    
      <xsl:template match="@* | node()">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()" />
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="level">
        <xsl:copy>
          <xsl:apply-templates select="@*" />
          <xsl:apply-templates mode="group"
                 select="*[generate-id() = 
                           generate-id(key('kDistinctChildren',
                                       concat(generate-id(..), '+', name()))[1])]" />
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="*" mode="group">
        <xsl:attribute name="{name()}">
          <xsl:apply-templates select="key('kDistinctChildren', 
                                         concat(generate-id(..), '+', name()))" 
                               mode="joinWithCommas"/>
        </xsl:attribute>
      </xsl:template>
    
      <xsl:template match="*" mode="joinWithCommas">
        <xsl:value-of select="concat(., substring(',', 1, position() != last()))"/>
      </xsl:template>
    
    </xsl:stylesheet>
    
    <levels>
      <level id="0" qd="NE" gate="99" zone="2" laydown="4" />
      <level id="0" qd="SE" gate="1" zone="6,5" laydown="1,2,3" />
    </levels>