xslt更改父级 - >孩子与孩子 - >亲

时间:2015-02-04 14:55:19

标签: xslt transform parent

我有这样的XML,需要用他们的地方改变parent-> child:

<root>
    <testcase name="Case1">
        <testsuite>Suite1</testsuite>
    </testcase>
    <testcase name="Case2">
        <testsuite>Suite1</testsuite>
    </testcase>

    <testcase name="Case3">
        <testsuite>Suite2</testsuite>
    </testcase>
    <testcase name="Case4">
        <testsuite>Suite2</testsuite>
    </testcase>
</root>

需要将其转换为此xml:

<root>
    <testsuite name="Suite1">
        <testcase>Case1</testcase>
        <testcase>Case2</testcase>
    </testsuite>

    <testsuite name="Suite2">
        <testcase>Case3</testcase>
        <testcase>Case4</testcase>
    </testsuite>
</root>

有人可以帮忙实现吗?

2 个答案:

答案 0 :(得分:1)

这是分组问题的一个例子,与大多数分组问题一样,首选方法(至少在XSLT 1.0中)是使用Muenchian分组:

<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="kSuite" match="testsuite" use="."/>

  <xsl:template match="/*">
    <xsl:copy>
      <xsl:apply-templates 
                      select="testcase/testsuite[generate-id() = 
                                                 generate-id(key('kSuite', .)[1])]"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="testsuite">
    <testsuite name="{.}">
      <xsl:apply-templates select="key('kSuite', .)/.." />
    </testsuite>
  </xsl:template>

  <xsl:template match="testcase">
    <xsl:copy>
      <xsl:value-of select="@name" />
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

在样本输入上运行此操作时,结果为:

<root>
  <testsuite name="Suite1">
    <testcase>Case1</testcase>
    <testcase>Case2</testcase>
  </testsuite>
  <testsuite name="Suite2">
    <testcase>Case3</testcase>
    <testcase>Case4</testcase>
  </testsuite>
</root>

答案 1 :(得分:1)

使用像Saxon 9或XmlPrime这样的XSLT 2.0处理器,您可以使用

<xsl:stylesheet version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs">

<xsl:output indent="yes"/>

<xsl:template match="/*">
  <xsl:copy>
    <xsl:for-each-group select="*/*" group-by=".">
      <xsl:copy>
        <xsl:attribute name="name" select="."/>
        <xsl:apply-templates select="current-group()/.."/>
      </xsl:copy>
    </xsl:for-each-group>
  </xsl:copy>
</xsl:template>

<xsl:template match="/*/*">
  <xsl:element name="{name()}">
    <xsl:value-of select="@name"/>
  </xsl:element>
</xsl:template>

</xsl:stylesheet>