java 使用XSLT比较两个xml文件

s71maibg  于 2023-03-06  发布在  Java
关注(0)|答案(3)|浏览(136)

我有两个XML文件file1.xml和file2.xml,我想比较这两个文件,并将内容的差异写入file3.txt。
它不工作,因为我有一个合成器错误与$file2/[ not(@key = $key1)]
我该怎么解决呢?

    • 文件1**
<node key="U">
  <node key="E" value="E1"/>
  <node key="B" value="B1"/>
  <node key="Z" value="Z1"/>
  <node key="T">
    <node key="Y">
      <node key="H" value="H1"/>
      <node key="C" value="C1"/>
      <node key="P" value="P1"/>
    </node>
  </node>
</node>

文件2**

<node key="U">
  <node key="E" value="E1"/>
  <node key="B" value="O1"/>
  <node key="G" value="Z1"/>
  <node key="T">
    <node key="Y2">
      <node key="H" value="H1"/>
      <node key="C1" value="C8"/>
      <node key="P" value="P1"/>
    </node>
  </node>
</node>
    • 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"  omit-xml-declaration="yes" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:variable name="file2" select="document('file2.xml')" />

<xsl:variable name="key1" select="@key" />
<xsl:variable name="key2" select="@key" />

<xsl:template match="@* | node()">
    <xsl:comment>"only in file1"</xsl:comment>
        <xsl:apply-templates select="[not(@key=$key2)]"/>
    <xsl:comment>"only in file2"</xsl:comment>
        <xsl:apply-templates select="$file2/[not(@key=$key1)]"/>
</xsl:template>
</xsl:stylesheet>
    • Java代码**
package XSLT;

import javax.xml.transform.*;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;

public class MainCompare {
    public static void main(String[] args) throws IOException, URISyntaxException, TransformerException {
        TransformerFactory factory = TransformerFactory.newInstance();
        Source xslt = new StreamSource(new File("transform2.xslt"));
        Transformer transformer = factory.newTransformer(xslt);

        Source text = new StreamSource(new File("file1.xml"));
        transformer.transform(text, new StreamResult(new File("file3.txt")));
    }
}

我想得到两个XML文件之间的差异。
想要的结果

"only in file1"

 key="B" value="B1"
 key="Z" value="Z1"
 key="Y"
 key="C" value="C1"

"only in file2"

  key="B" value="O1"
  key="G" value="Z1"
  key="Y2"
  key="C1" value="C8"
q3aa0525

q3aa05251#

下面是我快速拼凑出来的一些相对简单的结果:结果格式与你所展示的不同--但我看不出有什么好理由把同样的比较进行两次(如果你愿意,你可以把结果放入一个变量中,然后"打印"出来两次,每边一次)。

    • XSLT 1.0版本**
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:variable name="v1" select="//node" />
<xsl:variable name="v2" select="document('file2.xml')//node" />

<xsl:template match="/">
    <differences>
        <xsl:for-each select="$v1">
            <xsl:variable name="i" select="position()" />
            <xsl:variable name="n2" select="$v2[$i]" />
            <xsl:if test="@key != $n2/@key or @value != $n2/@value">
                <diff key1="{@key}" key2="{$n2/@key}" value1="{@value}" value2="{$n2/@value}"/>
            </xsl:if>
        </xsl:for-each>
    </differences>
</xsl:template>

</xsl:stylesheet>

应用于输入示例,结果将为:

    • 结果**
<?xml version="1.0" encoding="UTF-8"?>
<differences>
   <diff key1="B" key2="B" value1="B1" value2="O1"/>
   <diff key1="Z" key2="G" value1="Z1" value2="Z1"/>
   <diff key1="Y" key2="Y2" value1="" value2=""/>
   <diff key1="C" key2="C1" value1="C1" value2="C8"/>
</differences>
a7qyws3x

a7qyws3x2#

由于您使用的是Java,通常可以使用Saxon HE(目前支持的版本是10、11、12)和XSLT 3:

<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="text"/>

<xsl:key name="key" match="*" use="@key, @value" composite="yes" />

<xsl:template match="/">
<xsl:text>"only in file1"&#10;</xsl:text>
<xsl:value-of select="//*[not(key('key', (@key, @value), $file2))]!('key: ' || @key || ' value : ' || @value)" separator="&#10;"/>
<xsl:text>&#10;"only in file"&#10;</xsl:text>
<xsl:value-of select="$file2//*[not(key('key', (@key, @value), current()))]!('key: ' || @key || ' value : ' || @value)" separator="&#10;"/>
</xsl:template>

<xsl:variable name="file2" select="doc('file2.xml')"/>

</xsl:stylesheet>

结果

"only in file1"
key: B value : B1
key: Z value : Z1
key: Y value : 
key: C value : C1
"only in file"
key: B value : O1
key: G value : Z1
key: Y2 value : 
key: C1 value : C8
bnl4lu3b

bnl4lu3b3#

你问:
我在$file2/[not(@key=$key1)]中遇到合成器错误
嗯,是的,这不是一个有效的XPath表达式。我不能立即提供更正,因为我不知道它的目的是什么。当我查看样式表的其余部分时,它充满了类似的错误,表明您还没有掌握基本知识。恐怕我的第一React是,只有对XPath有更好知识的人才应该尝试这样复杂的任务。
与@michael.hor257k不同,我认为XSLT是完成这项工作的完美工具,尤其是XSLT 3.0等更高版本。但是,在开始编码之前,有两项重要工作要做:一个是更精确地定义需求,第二个是学习XSLT。2我建议在你解决像这样的难题之前先写一些简单的XSLT样式表。

相关问题