[英]XML merge nodes with XSLT
我有这样的xml文件:
<root>
<scenario name="film1">
<case name="aaa">
<test name="test1">ok</test>
</case>
<case name="bbb">
<test name="test2">not ok</test>
</case>
<case name="aaa">
<test name="test3">not ok</test>
</case>
<case name="bbb">
<test name="test66">ok</test>
</case>
</scenario>
</root>
当然,还有更多类似场景的节点,但是我希望每个场景都具有分组case
。 我期望这样的事情:
<root>
<scenario name="fil1">
<case name="aaa">
<test name="test1">ok</test>
<test name="test3">not ok</test>
</case>
<case name="bbb">
<test name="test2">not ok</test>
<test name="test66">ok</test>
</case>
</scenario>
</root>
我做了xslt文件:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="root">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="scenario">
<scenario>
<xsl:attribute name="name">
<xsl:value-of select="@name"/>
</xsl:attribute>
<xsl:apply-templates/>
</scenario>
</xsl:template>
<xsl:template match ="case">
<case>
<xsl:attribute name="name">
<xsl:value-of select="@name"/>
</xsl:attribute>
</case>
</xsl:template>
</xsl:stylesheet>
你知道我现在应该做什么吗?
我会用这样的东西...
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="root">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="scenario">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match ="case">
<xsl:param name="thisName">
<xsl:value-of select="@name" />
</xsl:param>
<xsl:if test=".=/root/scenario/case[@name=$thisName][1]">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates select="/root/scenario/case[@name=$thisName]/test" />
</xsl:copy>
</xsl:if>
</xsl:template>
<xsl:template match ="test">
<xsl:copy>
<xsl:apply-templates select="@*" />
</xsl:copy>
</xsl:template>
<xsl:template match ="@*">
<xsl:copy />
</xsl:template>
</xsl:stylesheet>
xslt 1.0中的标准方法-Muenchian分组。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:key name="case-by-name" match="case" use="@name"/>
<xsl:key name="test-by-case" match="test" use="parent::*/@name"/>
<xsl:template match="/root">
<xsl:copy>
<xsl:apply-templates select="*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="scenario">
<xsl:copy>
<xsl:copy-of select="@*"/>
<!-- process only first cases in groups -->
<xsl:apply-templates select="case[generate-id() = generate-id(key('case-by-name', @name)[1])]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="case">
<xsl:copy>
<xsl:copy-of select="@*"/>
<!-- copy all tests for corresponding case name -->
<xsl:copy-of select="key('test-by-case', @name)"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
您在问题中说,您希望对每种scenario
进行case
分组。 如果确实有多个scenario
元素,并且想要将case
元素归入每个这样的元素中,则需要使用一个串联键:
<xsl:key name="case" match="case" use="concat(../@name, '|', @name)" />
这意味着,如果您有两个具有相同name
case
元素,但在不同的scenario
元素中,则它们仍将分别分组。
现在,对于分组,对于scenario
每个case
语句,您需要找到在给定属性的键中首先出现的case
元素。 可以按照以下步骤进行:
<xsl:apply-templates select="case[generate-id() = generate-id(key('case', concat(../@name, '|', @name))[1])]" />
要分解...
key('case', concat(../@name, '|', @name))
-获取具有相同属性的所有元素
key('case', concat(../@name, '|', @name))[1]
-获取该列表的第一个元素
generate-id(key('case', concat(../@name, '|', @name))[1])
-为第一个元素生成唯一ID,因此可以将其与当前元素进行比较。
因此,有效地,您可以获得不同的元素。 然后,您可以再次使用键获取“组”中的项目
<xsl:for-each select="key('case', concat(../@name, '|', @name))">
试试这个XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="case" match="case" use="concat(../@name, '|', @name)" />
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="scenario">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:apply-templates select="case[generate-id() = generate-id(key('case', concat(../@name, '|', @name))[1])]" />
</xsl:copy>
</xsl:template>
<xsl:template match ="case">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:for-each select="key('case', concat(../@name, '|', @name))">
<xsl:apply-templates />
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
如评论所述,有关此方法的权威文章可以在http://www.jenitennison.com/xslt/grouping/muenchian.html上找到,因此值得阅读,然后重新阅读,然后再实践,直到您最终了解它为止。
另外,请注意Identity Transform的使用,这意味着如果您想要做的所有事情都希望在不做任何更改的情况下进行复制,则不必为每个特定元素编写模板。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.