我想使用XSL / XSLT计算两个XML文件或节点之间的差异。是否有现成的样式表或任何简单的方法?
答案 0 :(得分:6)
有趣的问题!我曾经试图做一些涉及两个XML源的类似事情,而我的经验是,没有办法。
您可以使用XSL的工具来包含用户构建的功能,并编写一些非常灵活的代码。但我真的看不到它。
如果我要做这样的事情,我会使用DOM4J并行处理这两个XML文件,这样我就可以轻松地以编程方式遍历代码并详细说明子查询。
尝试在XSLT中执行此操作将证明您是一个天才或让您陷入疯狂。
答案 1 :(得分:2)
XSLT是数据驱动的,也就是说,它从上到下遍历单个源XML文件,在XSL样式表中查找模板匹配。模板并不真正知道它们在数据中的位置,它们只是在匹配时运行它们的代码。您可以引用另一个XML源,但程序将根据原始源的遍历运行。
因此,当您到达<blarg>
的第n个子元素时,您可以使用<blarg>
函数在第二个XML中查找document()
的第n个子元素。但这样做的有用性取决于XML的结构以及您尝试进行的比较。
这种行为与大多数传统脚本相反,后者从上到下运行程序代码,在指示时调用数据文件。后者 - 拉取处理 - 是您可能需要比较两个XML源。只要存在差异,XSLT就会在比较中崩溃。
答案 2 :(得分:2)
这不是一个谜!以下是一般步骤:
@carillonator关于XSLT如何处理文档是正确的。因此,为了更容易,我们将文档的两个版本组合到一个文档中,您可以使用它来运行XSLT差异(您可以通过命令行使用bash,或者使用您正在使用的任何编程语言,甚至是另一个XSLT转换[pipe])。这只是一个封装:
<diff_container>
<version1>
... first version here
</version1>
<version2>
... second version here
</version2>
</diff_container>
然后我们通过XSLT diff运行这个文档,然后XSLT可以简单地遍历树并比较两个版本之间的节点。这可以从非常简单(一个元素改变?移动?删除?)变为半复杂。很好地理解XPath使得这很简单。
就像之前所说的那样,你在不同的环境中工作,所以与Diff Dog等工具相比,你是有限的。然而,在XSLT中使用该算法的好处也具有实际价值。
希望这有帮助。干杯!
答案 3 :(得分:2)
如果diff的意思是检查一个文档(或节点)中是否存在项目而不是另一个文档(或节点),则可以使用带有第三个参数的xpath key()函数
<?xml version="1.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="xsl xs">
<xsl:param name="doc2diff" required="yes"/>
<!-- docB is root node of the "second" document -->
<xsl:variable name="docB" select="document($doc2diff)"/>
<!-- docA is the root node of the first document -->
<xsl:variable name="docA" select="/"/>
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:key name="items" match="Item" use="someId"/>
<xsl:template match="/">
<ListOfItems>
<In_A_NotIn_B>
<xsl:apply-templates select="Item">
<xsl:with-param name="otherDocument" select="$docB"/>
</xsl:apply-templates>
</In_A_NotIn_B>
<In_B_NotIn_A>
<xsl:apply-templates select="Item">
<xsl:with-param name="otherDocument" select="$docA"/>
</xsl:apply-templates>
</In_B_NotIn_A>
</ListOfItems>
</xsl:template>
<xsl:template match="Item">
<xsl:param name="otherDocument"/>
<xsl:variable name="SOMEID" select="someId"/>
<xsl:if test="empty(key('items', $SOMEID, $otherDocument))">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>`
答案 4 :(得分:2)
这是我编写的样式表,用于比较节点和属性中不同顺序的两个XML文件,它将生成两个包含所有叶节点路径的有序列表的文本文件。使用任何文本比较工具来发现差异或增强XSLT以执行您想要的操作。
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" indent="no" omit-xml-declaration="yes" name="output" />
<xsl:param name="OTHERFILENAME">xml_file_to_diff.xml</xsl:param>
<xsl:param name="ORIGINAL_OUTPUT_FILENAME">ORIGINAL.txt</xsl:param>
<xsl:param name="OTHER_OUTPUT_FILENAME">OTHER.txt</xsl:param>
<xsl:template match="/">
<xsl:call-template name="convertXMLHierarchyToFullPath">
<xsl:with-param name="node" select="*"/>
<xsl:with-param name="filename" select="$ORIGINAL_OUTPUT_FILENAME"/>
</xsl:call-template>
<xsl:call-template name="convertXMLHierarchyToFullPath">
<xsl:with-param name="node" select="document($OTHERFILENAME)/*"/>
<xsl:with-param name="filename" select="$OTHER_OUTPUT_FILENAME"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="convertXMLHierarchyToFullPath">
<xsl:param name="node"/>
<xsl:param name="filename"/>
<xsl:variable name="unorderedFullPath">
<xsl:apply-templates select="$node"/>
</xsl:variable>
<xsl:result-document href="{$filename}" format="output">
<xsl:for-each select="$unorderedFullPath/*">
<xsl:sort select="@path" data-type="text"/>
<xsl:value-of select="@path"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:result-document>
</xsl:template>
<xsl:template match="*">
<xsl:if test="not(*)">
<leaf>
<xsl:attribute name="path">
<xsl:for-each select="ancestor-or-self::*">
<xsl:value-of select="name()"/>
<xsl:for-each select="@*">
<xsl:sort select="name()" data-type="text"/>
<xsl:text>[</xsl:text>
<xsl:value-of select="name()"/>
<xsl:text>:</xsl:text>
<xsl:value-of select="."/>
<xsl:text>]</xsl:text>
</xsl:for-each>
<xsl:text>/</xsl:text>
</xsl:for-each>
<xsl:value-of select="."/>
</xsl:attribute>
</leaf>
</xsl:if>
<xsl:apply-templates select="*"/>
</xsl:template>
答案 5 :(得分:1)
有很多方法可以做到这一点,但我不会说这很简单。
过去我使用了一个名为diffmk的开源实用程序,这会生成一个带有额外标签的输出XML,显示已添加/删除的内容......
我必须编写一个额外的样式表,然后将其转换为更易读的HTML报告。
像XMLSpy Diff dog这样的差异工具很好,但成本很高。
答案 6 :(得分:1)
最近发现这篇文章,但无论如何我会分享我的解决方案来解决这类问题。我有与@Vincent相同的需求:比较2个不同的XML文件,并快速查看它们之间的差异。快速差异有很多行匹配,因为文件没有排序,所以我决定使用XSLT对文件进行排序,然后使用WinMerge手动比较两个xml文件(一个简单的unix diff也可以完成这项工作)。
以下是对我的XML文件进行排序的XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*">
<xsl:sort select="name()" />
<xsl:sort select="@*" />
<xsl:sort select="*" />
<xsl:sort select="text()" />
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
答案 7 :(得分:0)
这是我最近写的一个Microsoft XSLT 1.0解决方案。它是一个无序的xml和属性比较,它返回b.xml中变量file2中找不到的输入文件中的项。如果您更改节点的顺序而不更改任何值,则不会认为存在差异。在我的github https://github.com/sflynn1812/xslt-diff-turbo
上查看