如果我在xml中有这个输入文件:
<root>
<node id="N1">
<fruit id="1">
<orange id="x" action="create">
<attribute>
<color>Orange</color>
<year>2000</year>
</attribute>
</orange>
</fruit>
<fruit id="1">
<orange id="x" action="create">
<attribute>
<color>Orange</color>
<condition>good</condition>
</attribute>
</orange>
</fruit>
</node>
</root>
这是预期的输出:
<root>
<node id="N1">
<fruit id="1">
<orange id="x" action="create">
<attribute>
<color>Orange</color>
<year>2000</year>
<condition>good</condition>
</attribute>
</orange>
</fruit>
<fruit id="1">
</fruit>
</node>
</root>
如何在两个兄弟之间进行简化:
另一种情况: 输入2:
<root>
<node id="N1">
<fruit id="1">
<orange id="x" action="create">
<attribute>
<color>Orange</color>
</attribute>
</orange>
</fruit>
<fruit id="1">
<orange id="x" action="create">
<attribute>
<color>Red</color>
<condition>good</condition>
</attribute>
</orange>
</fruit>
</node>
</root>
预期的输出:
<root>
<node id="N1">
<fruit id="1">
<orange id="x" action="create">
<attribute>
<color>Orange</color>
<condition>good</condition>
</attribute>
</orange>
</fruit>
<fruit id="1">
<orange id="x" action="create">
<attribute>
<color>Red</color>
</attribute>
</orange>
</fruit>
</node>
</root>
另一种情况:
<root>
<nodeA id="A">
<fruit id="1">
<orange id="x" action="delete" /> <!-- no attributes here -->
</fruit>
<fruit id="1">
<orange id="x" action="delete"/>
<orange id="y" action="delete" />
</fruit>
</nodeA>
</root>
预期产出:
<root>
<nodeA id="A">
<fruit id="1">
<orange id="x" action="delete" />
</fruit>
<fruit id="1">
<orange id="y" action="delete" />
</fruit>
</nodeA>
</root>
我希望这个例子给出明确的想法,请帮我转换文件。 感谢。
约翰
答案 0 :(得分:2)
John,这是一个有效的版本。它有些残酷和程序化,所以我想知道你是否真的想在XSLT中做这种逻辑。你走了:
以下样式表:
<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:key name="entity" match="node/*/*" use="concat(parent::*/@id, '_', @id, '_', @action)"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node/*/*[not(attribute)][generate-id() != generate-id(key('entity', concat(parent::*/@id, '_', @id, '_', @action))[1])]"/>
<xsl:template match="node/*/*[attribute]">
<xsl:variable name="attributes">
<xsl:copy>
<xsl:apply-templates select="@* | node()">
<xsl:with-param
name="mode"
select="generate-id() = generate-id(key('entity', concat(../@id, '_', @id, '_', @action))[1])"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:variable>
<xsl:if test="$attributes/*/attribute/*">
<xsl:copy-of select="$attributes"/>
</xsl:if>
</xsl:template>
<xsl:template match="node/*/*/attribute">
<xsl:param name="mode"/>
<xsl:variable name="all-attributes" select="key('entity', concat(../../@id, '_', ../@id, '_', ../@action))/attribute/*"/>
<xsl:copy>
<xsl:if test="$mode = true()">
<xsl:for-each-group select="$all-attributes" group-by="local-name()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:for-each-group>
</xsl:if>
<xsl:if test="$mode = false()">
<xsl:for-each select="*">
<xsl:variable
name="same-name-attr"
select="$all-attributes[local-name() = current()/local-name()][count(. | current()/preceding::*) = count(current()/preceding::*)]"/>
<xsl:if test="$same-name-attr and not(. = $same-name-attr)">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:if>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
会产生以下结果:
<root>
<node id="N1">
<fruit id="1">
<orange id="x" action="create">
<attribute>
<color>Orange</color>
<year>2000</year>
<condition>good</condition>
<new>!!</new>
</attribute>
</orange>
</fruit>
<fruit id="1">
<orange id="x" action="create">
<attribute>
<color>Red</color>
</attribute>
</orange>
</fruit>
<fruit id="1">
<orange id="x" action="create">
<attribute>
<color>Blue</color>
</attribute>
</orange>
</fruit>
<fruit id="1">
<orange id="x" action="create">
<attribute>
<condition>ugly</condition>
</attribute>
</orange>
</fruit>
<fruit id="1"/>
</node>
</root>
所有唯一属性都会被提取到第一次出现的create
操作中,只有具有不同值属性的属性才会保留在following::
个节点中。如果该节点没有任何新内容可以添加它,那么它就会被遗忘。以下是我如何确定该属性是否值得为后续事件保留。如果之前没有看到该属性,那么它已被拉到第一次出现,所以我们跳过它。如果之前已经看到它(=它在preceding
轴上的同名属性集合中)并且具有不同的文本值,那么我们就保留它。
你想要做的选择器逐渐变得越来越复杂,所以我不得不使用临时变量基本上让模板对它进行了检查,然后检查是否有任何结果然后决定是否值得复制到结果树。可能有一种方法可以将此逻辑转换为匹配谓词,但我不确定它是否更具可读性。我希望这是有道理的。
更新我更新了解决方案以适用于您的无属性角落案例。我基本上不得不沉默重复的no - attribute
节点,并使主模板更具体,只适用于attribute
s的节点。将“重复”with-attribute节点的无属性节点将使用主要属性合并逻辑进行静默。需要保留的no - attribute
节点将使用默认的标识转换进行复制。