Xml 如何修复XSLT中的这种消除转换?
我有以下意见:Xml 如何修复XSLT中的这种消除转换?,xml,xslt,Xml,Xslt,我有以下意见: <root> <sector> <nodeA id="a"> <section id="i"> <item1 id="1" method="delete"/> <item1 id="1" method="create"> <somechild>
<root>
<sector>
<nodeA id="a">
<section id="i">
<item1 id="1" method="delete"/>
<item1 id="1" method="create">
<somechild>a</somechild>
</item1>
<item1 id="1" method="change">
<somechild>a</somechild>
</item1>
</section>
<section id="i">
<item1 id="1" method="change">
<somechild>a</somechild>
</item1>
</section>
<section id="i">
<item1 id="1" method="delete"/>
<item1 id="1" method="create">
<somechild>a</somechild>
</item1>
</section>
</nodeA>
</sector>
</root>
A.
A.
A.
A.
我的XSL是:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="*[not(.//*[@id!=''])][@method='delete']">
<xsl:if test="not(following::*[not(.//*[@id!=''])][@id=current()/@id][../@id = current()/../@id][generate-id(../..) = generate-id(current()/../..)])"/>
</xsl:template>
<xsl:template match="*[not(.//*[@id!=''])][@method!='delete']">
<xsl:if test="not(following::*[not(.//*[@id!=''])][@method='delete'][@id=current()/@id][../@id = current()/../@id][generate-id(../..) = generate-id(current()/../..)])"/>
</xsl:template>
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我的输出:
<root>
<sector>
<nodeA id="a">
<section id="i">
</section>
<section id="i">
</section>
<section id="i">
</section>
</nodeA>
</sector>
</root>
预期输出:
<root>
<sector>
<nodeA id="a">
<section id="i">
<item1 id="1" method="delete"/> <!-- leave this node -->
</section>
<section id="i">
</section>
<section id="i">
<item1 id="1" method="create"> <!-- leave this node -->
<somechild>a</somechild>
</item1>
</section>
</nodeA>
</sector>
</root>
A.
我想删除元素与节点的组合
- 一个方法创建,然后是一个或多个
和@id
,并且必须位于相同的父项下,例如
约翰约翰,我有一个解决方案,你可能喜欢,也可能不喜欢。我做了一个“优化”来简化一些事情。我认为,既然您将那些具有相同
@id
的节
节点视为相同的节点,那么您可能不介意在结果文档中看到它们全部合并为一个。看看这是否可以接受
以下是XSLT 2.0的转换:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="nodeA">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:for-each-group select="*" group-by="concat(name(), '|', @id)">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:variable name="merged">
<xsl:for-each-group select="current-group()/*"
group-by="concat(name(), '|', @id)">
<xsl:copy-of select="current-group()"/>
</xsl:for-each-group>
</xsl:variable>
<xsl:apply-templates select="$merged/*"/>
</xsl:copy>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="*[@method = 'create']
[following-sibling::*[@method = 'change']
[following-sibling::*[@method = 'delete']]]"/>
<xsl:template match="*[@method = 'change']
[preceding-sibling::*[@method = 'create']]
[following-sibling::*[@method = 'delete']]"/>
<xsl:template match="*[@method = 'delete']
[preceding-sibling::*[@method = 'change']
[preceding-sibling::*[@method = 'create']]]"/>
</xsl:stylesheet>
应用于输入文档时,会生成:
<root>
<sector>
<nodeA id="a">
<section id="i">
<item1 id="1" method="delete"/>
<item1 id="1" method="create">
<somechild>a</somechild>
</item1>
</section>
</nodeA>
</sector>
</root>
A.
我认为将那些
item1
节点折叠成一个简单有序的列表,然后过滤掉想要删除的序列会容易得多。我必须将它们复制到一个变量中,以便从原始文档树中“分离”,否则那些同级轴将在原始父节点中查看。一旦您拥有来自“相同”父节点的“相同”item1
节点的平面列表,过滤create-change-delete序列真是小菜一碟。我刚刚将您的规则直接转换为XPath谓词-一个用于create
,后面是change
,后面是delete
,另一个用于change
,前面是create
,后面是delete
,最后一个是delete
,前面是change
,前面是create
。它们都“已知”为相同的name()
和@id
,并且来自相同的(name()
和@id
)父级,因此我们不必检查该部分。这并不容易,但它在xslt 1.0中工作
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<!--
copies all nodes with id
if there first preceding delete followed by the first preceding create
-->
<xsl:template match="*[not(.//*[@id!=''])]">
<xsl:variable name="id" select="@id"/>
<xsl:variable name="parentId" select="../@id"/>
<xsl:variable name="precedings" select="preceding::*[@id=$id][../@id=$parentId]"/>
<xsl:variable name="lastDelete" select="($precedings[@method='delete'])[last()]"/>
<xsl:variable name="lastCreate" select="($precedings[@method='create'])[last()]"/>
<xsl:variable name="openCreate" select="$lastDelete[following::* = $lastCreate] or (not($lastDelete) and $lastCreate)"/>
<xsl:if test="not(following::*[@id=$id][../@id=$parentId][@method='delete'] and $openCreate)">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:if>
</xsl:template>
<!--
copies all deletes, if they have no preceding creates
-->
<xsl:template match="*[not(.//*[@id!=''])][@method='delete']" priority="10">
<xsl:variable name="id" select="@id"/>
<xsl:variable name="parentId" select="../@id"/>
<xsl:variable name="precedings" select="preceding::*[@id=$id][../@id=$parentId]"/>
<xsl:variable name="precCreate" select="$precedings[@method='create']"/>
<xsl:if test="not($precCreate)">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:if>
</xsl:template>
<!--
copies all creates, if they have no following deletes
-->
<xsl:template match="*[not(.//*[@id!=''])][@method='create']" priority="10">
<xsl:variable name="id" select="@id"/>
<xsl:variable name="parentId" select="../@id"/>
<xsl:variable name="followings" select="following::*[@id=$id][../@id=$parentId]"/>
<xsl:variable name="followDelete" select="$followings[@method='delete']"/>
<xsl:if test="not($followDelete)">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:if>
</xsl:template>
<!--
copies all nodes
-->
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
测试它。。。没有保证 你的问题变得越来越棘手:)它有效,但我相信它缺少一个要求。那些属于[@id=$id]
的item1
节点也应该属于“同一”父节点,才有资格进行“合并”。类似于[parent::*/@id=(current()/parent:::*/@id)]
的东西需要添加到那些[@id=$id]
谓词中。然后我使用了创建-更改-删除序列的各种组合,结果与John的要求不匹配。我想你的转换需要更多的测试和调整,但你肯定在这方面有所进展。好吧,我做了一些改变:我误解了第二个要求,我修正了它。还有一些错误。谢谢你的解决方案。我仍在尝试实现它以匹配更大的xml输入。我会再打给你的。再次感谢