如何比较两个不同行中具有相同数据的xml文件?

如何比较两个不同行中具有相同数据的xml文件?

我有两个文件具有相同的数据但在不同的行中。

文件一:

<Identities>
    <Identity>
        <Id>048206031415072010Comcast.USR8JR</Id>
        <UID>ccp_test_79</UID>
        <DisplayName>JOSH CCP</DisplayName>
        <FirstName>JOSH</FirstName>
        <LastName>CCP</LastName>
        <Role>P</Role>
        <LoginStatus>C</LoginStatus>
    </Identity>
    <Identity>
        <Id>089612381523032011Comcast.USR1JR</Id>
        <UID>94701_account1</UID>
        <DisplayName>account1</DisplayName>
        <FirstName>account1</FirstName>
        <LastName>94701</LastName>
        <Role>S</Role>
        <LoginStatus>C</LoginStatus>
    </Identity>
</Identities>

文件2:

<Identities>
    <Identity>
        <Id>089612381523032011Comcast.USR1JR</Id>
        <UID>94701_account1</UID>
        <DisplayName>account1</DisplayName>
        <FirstName>account1</FirstName>
        <LastName>94701</LastName>
        <Role>S</Role>
        <LoginStatus>C</LoginStatus>
    </Identity>
    <Identity>
        <Id>048206031415072010Comcast.USR8JR</Id>
        <UID>ccp_test_79</UID>
        <DisplayName>JOSH CCP</DisplayName>
        <FirstName>JOSH</FirstName>
        <LastName>CCP</LastName>
        <Role>P</Role>
        <LoginStatus>C</LoginStatus>
    </Identity>
</Identities>

如果我使用diff file1 file2命令,我会得到以下响应:

1,10d0
<     <Identities>
<         <Identity>
<             <Id>048206031415072010Comcast.USR8JR</Id>
<             <UID>ccp_test_79</UID>
<             <DisplayName>JOSH CCP</DisplayName>
<             <FirstName>JOSH</FirstName>
<             <LastName>CCP</LastName>
<             <Role>P</Role>
<             <LoginStatus>C</LoginStatus>
<         </Identity>
20a11,20
>     <Identities>
>         <Identity>
>             <Id>048206031415072010Comcast.USR8JR</Id>
>             <UID>ccp_test_79</UID>
>             <DisplayName>JOSH CCP</DisplayName>
>             <FirstName>JOSH</FirstName>
>             <LastName>CCP</LastName>
>             <Role>P</Role>
>             <LoginStatus>C</LoginStatus>
>         </Identity>

但我不需要得到任何区别,因为这些文件在不同行中具有相同的数据。

答案1

您可以借助一个小的 Python 脚本来实现您想要的目标(您需要安装 Python,以及lxml工具包)。

tagsort.py:

#!/usr/bin/python

import sys
from lxml import etree

filename, tag = sys.argv[1:]

doc = etree.parse(filename, etree.XMLParser(remove_blank_text=True))
root = doc.getroot()
root[:] = sorted(root, key=lambda el: el.findtext(tag))
print etree.tostring(doc, pretty_print=True)

该脚本根据第二级元素的内容对 XML 文档根下的第一级元素进行排序,并将结果发送到 stdout。它的名字是这样的:

$ python tagsort.py filename tag

一旦你掌握了它,你就可以使用流程替代根据其输出获取差异(我在示例文件中添加了一个元素并更改了另一个元素以显示非空结果):

$ diff <(python tagsort.py file1 Id) <(python tagsort.py file2 Id)
4a5
>     <AddedTag>Something</AddedTag>
17c18
<     <Role>X</Role>
---
>     <Role>S</Role>

答案2

我也遇到了类似的问题,最终我发现:https://superuser.com/questions/79920/how-can-i-diff-two-xml-files

那篇文章建议先进行规范的 xml 排序,然后再进行比较。如果您使用的是 Linux、Mac,或者安装了类似 cygwin 的 Windows 系统,以下内容应该适合您:

$ xmllint --c14n File1.xml > 1.xml
$ xmllint --c14n File2.xml > 2.xml
$ diff 1.xml 2.xml

答案3

它被标记为 shell,但老实说,我更喜欢使用带有解析器的脚本语言。在这种情况perl下与XML::Twig.

事情是这样的:

#!/usr/bin/env perl
use strict;
use warnings;

use XML::Twig;

sub compare_by_identity {
   my ( $first, $second ) = @_;
   foreach my $identity ( $first->get_xpath('//Identity') ) {
      my $id = $identity->first_child_text('Id');

      print $id, "\n";
      my $compare_to =
        $second->get_xpath( "//Identity/Id[string()=\"$id\"]/..", 0 );
      if ($compare_to) {
         print "Matching element found for ID $id\n";
         foreach my $element ( $identity->children ) {
            my $tag  = $element->tag;
            my $text = $element->text;
            if ( not $element->text eq $compare_to->first_child_text($tag) ) {
               print "$id, $tag has value $text which doesn't match: ",
                 $compare_to->first_child_text($tag), "\n";
            }
         }
      }
      else {
         print "No matching element for Id $id\n";
      }
   }
}

my $first_file  = XML::Twig->new->parsefile('test1.xml');
my $second_file = XML::Twig->new->parsefile('test2.xml');

compare_by_identity( $first_file,  $second_file );
compare_by_identity( $second_file, $first_file );

我一次明确地比较一个“身份”元素,并检查一个元素中的所有字段是否存在于另一个元素中,并且具有相同的值。

然后反转,因为第二个文件可能有额外的条目。

答案4

使用xq来自https://kislyuk.github.io/yq/:

xq -sS '.[].Identities.Identity |= sort | .[0] == .[1]' file1.xml file2.xml

这会读取两个 XML 文件并将它们转换为 JSON。每个文件都显示为顶级数组的单独元素,因此在上面的示例中,file1.xml将在 中找到.[0]并将file2.xml在 中找到.[1](这是由该-s选项完成的)。由于该选项,每个文件的键将自动排序-S

对每个文档的身份进行排序,然后比较两个文档。

输出将是true问题中提供的数据的字符串,或者false是否对任一文档进行了单个更改。

您可以在 shell 测试中使用它,如下所示:

if xq -e -sS '.[].Identities.Identity |= sort | .[0] == .[1]' file1.xml file2.xml >/dev/null
then
    echo 'documents are the same'
else
    echo 'documents are different'
fi

如果最后一条语句有一个,则该-e选项导致 的退出状态xq为零真的布尔值。


作为参考,为问题中的两个文件内部创建的 JSON 文档如下所示:

[
  {
    "Identities": {
      "Identity": [
        {
          "DisplayName": "JOSH CCP",
          "FirstName": "JOSH",
          "Id": "48206031415072010Comcast.USR8JR",
          "LastName": "CCP",
          "LoginStatus": "C",
          "Role": "P",
          "UID": "ccp_test_79"
        },
        {
          "DisplayName": "account1",
          "FirstName": "account1",
          "Id": "089612381523032011Comcast.USR1JR",
          "LastName": "94701",
          "LoginStatus": "C",
          "Role": "S",
          "UID": "94701_account1"
        }
      ]
    }
  },
  {
    "Identities": {
      "Identity": [
        {
          "DisplayName": "account1",
          "FirstName": "account1",
          "Id": "089612381523032011Comcast.USR1JR",
          "LastName": "94701",
          "LoginStatus": "C",
          "Role": "S",
          "UID": "94701_account1"
        },
        {
          "DisplayName": "JOSH CCP",
          "FirstName": "JOSH",
          "Id": "048206031415072010Comcast.USR8JR",
          "LastName": "CCP",
          "LoginStatus": "C",
          "Role": "P",
          "UID": "ccp_test_79"
        }
      ]
    }
  }
]

相关内容