代码之家  ›  专栏  ›  技术社区  ›  Andrew Garrison

比较XML忽略子元素的顺序

  •  14
  • Andrew Garrison  · 技术社区  · 16 年前

    有人知道一个工具可以比较两个XML文档吗。确保嘲弄还有更多。我需要的东西,将确保文件1中的每个节点也在文件2中,无论顺序。我原以为XMLSpy会使用忽略子节点顺序选项来实现这一点,但事实并非如此。以下内容将被视为相同:

    <Node>
        <Child name="Alpha"/>
        <Child name="Beta"/>
        <Child name="Charlie"/>
    </Node>
    
    <Node>
        <Child name="Beta"/>
        <Child name="Charlie"/>
        <Child name="Alpha"/>
    </Node>
    
    11 回复  |  直到 16 年前
        1
  •  12
  •   Community Mohan Dere    5 年前

    我为此编写了一个简单的python工具,名为 xmldiffs :

    比较两个XML文件,忽略元素和属性顺序。

    xmldiffs [OPTION] FILE1 FILE2

    任何额外的选项都会传递给 diff 指挥部。

    https://github.com/joh/xmldiffs

        2
  •  8
  •   LockeCJ    7 年前

    具有 Beyond Compare File Formats -设置 XML Sort 转换。使用此选项,XML子项将在差异之前排序。

    available .

        3
  •  3
  •   Rob Vermeulen    16 年前

    你可能想用谷歌搜索“ XML diff tool “,这将给您带来更充分的结果。 其中之一是 OxygenXml XML Diff and Patch Tool .

    祝你好运

        4
  •  2
  •   Chris R    13 年前

    XMLUnit 因为它可以满足不同顺序的元素。

        5
  •  1
  •   dalelane    11 年前

    今天晚上我也有类似的需求,找不到符合我要求的东西。

    我的解决方法是对我想要区分的两个XML文件进行排序,按元素名称的字母顺序进行排序。一旦它们的顺序一致,我就可以使用常规的VisualDiff工具来区分这两个已排序的文件。

    如果这种方法对其他任何人都有用,那么我已经分享了我编写的python脚本,用于在 http://dalelane.co.uk/blog/?p=3225

        6
  •  0
  •   Community Mohan Dere    9 年前

    我最近在这里给出了类似的回答( Open source command line tool for Linux to diff XML files ignoring element order

    <xsl:stylesheet version="2.0"
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    
                    xmlns:set="http://exslt.org/sets"
    
                    xmlns:primary="primary"
                    xmlns:control="control"
    
                    xmlns:util="util"
    
                    exclude-result-prefixes="xsl xs set primary control">
    
        <!-- xml diff tool
    
             import this stylesheet from another and call the "compare" template with two args:
    
                 primary: the root of the primary tree to submit to comparison
                 control: the root of the control tree to compare against
    
             the two trees will be walked together. the primary tree will be walked in document order, matching elements
             and attributes from the control tree along the way, building a tree of common content, with appendages
             containing primary and control only content. that tree will then be used to generate the diff.
    
             the process of matching involves finding, for an element or attribute in the primary tree, the
             equivalent element or attribute in the control tree, *at the same level*, and *regardless of ordering*.
    
                 matching logic is encoded as templates with mode="find-match", providing a hook to wire in specific
                 matching logic for particular elements or attributes. for example, an element may "match" based on an
                 @id attribute value, irrespective of element ordering; encode this in a mode="find-match" template.
    
                 the treatment of diffs is encoded as templates with mode="primary-only" and "control-only", providing
                 hooks for alternate behavior upon encountering differences.
    
              -->
    
        <xsl:output method="text"/>
    
        <xsl:strip-space elements="*"/>
    
        <xsl:param name="full" select="false()"/><!-- whether to render the full doc, as opposed to just diffs -->
    
        <xsl:template match="/">
            <xsl:call-template name="compare">
                <xsl:with-param name="primary" select="*/*[1]"/><!-- first child of root element, for example -->
                <xsl:with-param name="control" select="*/*[2]"/><!-- second child of root element, for example -->
            </xsl:call-template>
        </xsl:template>
    
        <!-- OVERRIDES: templates that can be overridden to provide targeted matching logic and diff treatment -->
    
        <!-- default find-match template for elements
             (by default, for "complex" elements, name has to match, for "simple" elements, name and value do)
             for context node (from "primary"), choose from among $candidates (from "control") which one matches
             (override with more specific match patterns to effect alternate behavior for targeted elements)
             -->
        <xsl:template match="*" mode="find-match" as="element()?">
            <xsl:param name="candidates" as="element()*"/>
            <xsl:choose>
                <xsl:when test="text() and count(node()) = 1"><!-- simple content -->
                    <xsl:sequence select="$candidates[node-name(.) = node-name(current())][text() and count(node()) = 1][. = current()][1]"/>
                </xsl:when>
                <xsl:when test="not(node())"><!-- empty -->
                    <xsl:sequence select="$candidates[node-name(.) = node-name(current())][not(node())][1]"/>
                </xsl:when>
                <xsl:otherwise><!-- presumably complex content -->
                    <xsl:sequence select="$candidates[node-name(.) = node-name(current())][1]"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:template>
    
        <!-- default find-match template for attributes
             (by default, name and value have to match)
             for context attr (from "primary"), choose from among $candidates (from "control") which one matches
             (override with more specific match patterns to effect alternate behavior for targeted attributes)
             -->
        <xsl:template match="@*" mode="find-match" as="attribute()?">
            <xsl:param name="candidates" as="attribute()*"/>
            <xsl:sequence select="$candidates[. = current()][node-name(.) = node-name(current())][1]"/>
        </xsl:template>
    
        <!-- default primary-only template (override with more specific match patterns to effect alternate behavior) -->
        <xsl:template match="@* | *" mode="primary-only">
            <xsl:apply-templates select="." mode="illegal-primary-only"/>
        </xsl:template>
    
        <!-- write out a primary-only diff -->
        <xsl:template match="@* | *" mode="illegal-primary-only">
            <primary:only>
                <xsl:copy-of select="."/>
            </primary:only>
        </xsl:template>
    
        <!-- default control-only template (override with more specific match patterns to effect alternate behavior) -->
        <xsl:template match="@* | *" mode="control-only">
            <xsl:apply-templates select="." mode="illegal-control-only"/>
        </xsl:template>
    
        <!-- write out a control-only diff -->
        <xsl:template match="@* | *" mode="illegal-control-only">
            <control:only>
                <xsl:copy-of select="."/>
            </control:only>
        </xsl:template>
    
        <!-- end OVERRIDES -->
    
        <!-- MACHINERY: for walking the primary and control trees together, finding matches and recursing -->
    
        <!-- compare "primary" and "control" trees (this is the root of comparison, so CALL THIS ONE !) -->
        <xsl:template name="compare">
            <xsl:param name="primary"/>
            <xsl:param name="control"/>
    
            <!-- write the xml diff into a variable -->
            <xsl:variable name="diff">
                <xsl:call-template name="match-children">
                    <xsl:with-param name="primary" select="$primary"/>
                    <xsl:with-param name="control" select="$control"/>
                </xsl:call-template>
            </xsl:variable>
    
            <!-- "print" the xml diff as textual output -->
            <xsl:apply-templates select="$diff" mode="print">
                <xsl:with-param name="render" select="$full"/>
            </xsl:apply-templates>
    
        </xsl:template>
    
        <!-- assume primary (context) element and control element match, so render the "common" element and recurse -->
        <xsl:template match="*" mode="common">
            <xsl:param name="control"/>
    
            <xsl:copy>
                <xsl:call-template name="match-attributes">
                    <xsl:with-param name="primary" select="@*"/>
                    <xsl:with-param name="control" select="$control/@*"/>
                </xsl:call-template>
    
                <xsl:choose>
                    <xsl:when test="text() and count(node()) = 1">
                        <xsl:value-of select="."/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:call-template name="match-children">
                            <xsl:with-param name="primary" select="*"/>
                            <xsl:with-param name="control" select="$control/*"/>
                        </xsl:call-template>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:copy>
    
        </xsl:template>
    
        <!-- find matches between collections of attributes in primary vs control -->
        <xsl:template name="match-attributes">
            <xsl:param name="primary" as="attribute()*"/>
            <xsl:param name="control" as="attribute()*"/>
            <xsl:param name="primaryCollecting" as="attribute()*"/>
    
            <xsl:choose>
                <xsl:when test="$primary and $control">
                    <xsl:variable name="this" select="$primary[1]"/>
                    <xsl:variable name="match" as="attribute()?">
                        <xsl:apply-templates select="$this" mode="find-match">
                            <xsl:with-param name="candidates" select="$control"/>
                        </xsl:apply-templates>
                    </xsl:variable>
    
                    <xsl:choose>
                        <xsl:when test="$match">
                            <xsl:copy-of select="$this"/>
                            <xsl:call-template name="match-attributes">
                                <xsl:with-param name="primary" select="subsequence($primary, 2)"/>
                                <xsl:with-param name="control" select="remove($control, 1 + count(set:leading($control, $match)))"/>
                                <xsl:with-param name="primaryCollecting" select="$primaryCollecting"/>
                            </xsl:call-template>
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:call-template name="match-attributes">
                                <xsl:with-param name="primary" select="subsequence($primary, 2)"/>
                                <xsl:with-param name="control" select="$control"/>
                                <xsl:with-param name="primaryCollecting" select="$primaryCollecting | $this"/>
                            </xsl:call-template>
                        </xsl:otherwise>
                    </xsl:choose>
    
                </xsl:when>
                <xsl:otherwise>
                    <xsl:if test="$primaryCollecting | $primary">
                        <xsl:apply-templates select="$primaryCollecting | $primary" mode="primary-only"/>
                    </xsl:if>
                    <xsl:if test="$control">
                        <xsl:apply-templates select="$control" mode="control-only"/>
                    </xsl:if>
                </xsl:otherwise>
            </xsl:choose>
    
        </xsl:template>
    
        <!-- find matches between collections of elements in primary vs control -->
        <xsl:template name="match-children">
            <xsl:param name="primary" as="node()*"/>
            <xsl:param name="control" as="element()*"/>
    
            <xsl:variable name="this" select="$primary[1]" as="node()?"/>
    
            <xsl:choose>
                <xsl:when test="$primary and $control">
                    <xsl:variable name="match" as="element()?">
                        <xsl:apply-templates select="$this" mode="find-match">
                            <xsl:with-param name="candidates" select="$control"/>
                        </xsl:apply-templates>
                    </xsl:variable>
    
                    <xsl:choose>
                        <xsl:when test="$match">
                            <xsl:apply-templates select="$this" mode="common">
                                <xsl:with-param name="control" select="$match"/>
                            </xsl:apply-templates>
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:apply-templates select="$this" mode="primary-only"/>
                        </xsl:otherwise>
                    </xsl:choose>
                    <xsl:call-template name="match-children">
                        <xsl:with-param name="primary" select="subsequence($primary, 2)"/>
                        <xsl:with-param name="control" select="if (not($match)) then $control else remove($control, 1 + count(set:leading($control, $match)))"/>
                    </xsl:call-template>
                </xsl:when>
                <xsl:when test="$primary">
                    <xsl:apply-templates select="$primary" mode="primary-only"/>
                </xsl:when>
                <xsl:when test="$control">
                    <xsl:apply-templates select="$control" mode="control-only"/>
                </xsl:when>
            </xsl:choose>
    
        </xsl:template>
    
        <!-- end MACHINERY -->
    
        <!-- PRINTERS: print templates for writing out the diff -->
    
        <xsl:template match="*" mode="print">
            <xsl:param name="depth" select="-1"/>
            <xsl:param name="render" select="false()"/>
            <xsl:param name="lineLeader" select="' '"/>
            <xsl:param name="rest" as="element()*"/>
    
            <xsl:if test="$render or descendant::primary:* or descendant::control:*">
    
                <xsl:call-template name="whitespace">
                    <xsl:with-param name="indent" select="$depth"/>
                    <xsl:with-param name="leadChar" select="$lineLeader"/>
                </xsl:call-template>
                <xsl:text>&lt;</xsl:text>
                <xsl:value-of select="name(.)"/>
    
                <xsl:apply-templates select="@* | primary:*[@*] | control:*[@*]" mode="print">
                    <xsl:with-param name="depth" select="$depth"/>
                    <xsl:with-param name="render" select="$render"/>
                    <xsl:with-param name="lineLeader" select="$lineLeader"/>
                </xsl:apply-templates>
    
                <xsl:choose>
                    <xsl:when test="text() and count(node()) = 1"><!-- field element (just textual content) -->
                        <xsl:text>&gt;</xsl:text>
                        <xsl:value-of select="."/>
                        <xsl:text>&lt;/</xsl:text>
                        <xsl:value-of select="name(.)"/>
                        <xsl:text>&gt;</xsl:text>
                    </xsl:when>
                    <xsl:when test="count(node()) = 0"><!-- empty (self-closing) element -->
                        <xsl:text>/&gt;</xsl:text>
                    </xsl:when>
                    <xsl:otherwise><!-- complex content -->
                        <xsl:text>&gt;&#10;</xsl:text>
                        <xsl:apply-templates select="*[not(self::primary:* and @*) and not(self::control:* and @*)]" mode="print">
                            <xsl:with-param name="depth" select="$depth + 1"/>
                            <xsl:with-param name="render" select="$render"/>
                            <xsl:with-param name="lineLeader" select="$lineLeader"/>
                        </xsl:apply-templates>
                        <xsl:call-template name="whitespace">
                            <xsl:with-param name="indent" select="$depth"/>
                            <xsl:with-param name="leadChar" select="$lineLeader"/>
                        </xsl:call-template>
                        <xsl:text>&lt;/</xsl:text>
                        <xsl:value-of select="name(.)"/>
                        <xsl:text>&gt;</xsl:text>
                    </xsl:otherwise>
                </xsl:choose>
    
                <xsl:text>&#10;</xsl:text>
    
            </xsl:if>
    
            <!-- write the rest of the elements, if any -->
            <xsl:apply-templates select="$rest" mode="print">
                <xsl:with-param name="depth" select="$depth"/>
                <xsl:with-param name="render" select="$render"/>
                <xsl:with-param name="lineLeader" select="$lineLeader"/>
                <xsl:with-param name="rest" select="()"/><!-- avoid implicit param pass to recursive call! -->
            </xsl:apply-templates>
    
        </xsl:template>
    
        <xsl:template match="@*" mode="print">
            <xsl:param name="depth" select="0"/>
            <xsl:param name="render" select="false()"/>
            <xsl:param name="lineLeader" select="' '"/>
            <xsl:param name="rest" as="attribute()*"/>
    
            <xsl:if test="$render">
    
                <xsl:text>&#10;</xsl:text>
                <xsl:call-template name="whitespace">
                    <xsl:with-param name="indent" select="$depth + 3"/>
                    <xsl:with-param name="leadChar" select="$lineLeader"/>
                </xsl:call-template>
                <xsl:value-of select="name(.)"/>
                <xsl:text>="</xsl:text>
                <xsl:value-of select="."/>
                <xsl:text>"</xsl:text>
            </xsl:if>
    
            <xsl:apply-templates select="$rest" mode="print">
                <xsl:with-param name="depth" select="$depth"/>
                <xsl:with-param name="render" select="$render"/>
                <xsl:with-param name="lineLeader" select="$lineLeader"/>
                <xsl:with-param name="rest" select="()"/><!-- avoid implicit param pass to recursive call! -->
            </xsl:apply-templates>
    
        </xsl:template>
    
        <xsl:template match="primary:* | control:*" mode="print">
            <xsl:param name="depth"/>
    
            <xsl:variable name="diffType" select="util:diff-type(.)"/>
            <xsl:variable name="primary" select="self::primary:*"/>
            <xsl:variable name="lineLeader" select="if ($primary) then '+' else '-'"/>
    
            <!-- only if this is the first in a sequence of control::* elements, since the rest are handled along with the first... -->
            <xsl:if test="util:diff-type(preceding-sibling::*[1]) != $diffType">
                <xsl:if test="@*">
                    <xsl:text>&#10;</xsl:text>
                </xsl:if>
                <xsl:call-template name="diffspace">
                    <xsl:with-param name="indent" select="if (@*) then $depth + 3 else $depth"/>
                    <xsl:with-param name="primary" select="$primary"/>
                </xsl:call-template>
                <b><i>&lt;!-- ... --&gt;</i></b><!-- something to identify diff sections in output -->
                <xsl:if test="node()">
                    <xsl:text>&#10;</xsl:text>
                </xsl:if>
                <xsl:variable name="rest" select="set:leading(following-sibling::*, following-sibling::*[util:diff-type(.) != $diffType])"/>
                <xsl:apply-templates select="@* | node()" mode="print">
                    <xsl:with-param name="depth" select="$depth"/>
                    <xsl:with-param name="render" select="true()"/>
                    <xsl:with-param name="lineLeader" select="$lineLeader"/>
                    <xsl:with-param name="rest" select="$rest/@* | $rest/*"/>
                </xsl:apply-templates>
            </xsl:if>
        </xsl:template>
    
        <xsl:template name="whitespace">
            <xsl:param name="indent" select="0" as="xs:integer"/>
            <xsl:param name="leadChar" select="' '"/>
            <xsl:choose>
                <xsl:when test="$indent > 0">
                    <xsl:value-of select="$leadChar"/>
                    <xsl:text> </xsl:text>
                    <xsl:for-each select="0 to $indent - 1">
                        <xsl:text>  </xsl:text>
                    </xsl:for-each>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:for-each select="0 to $indent">
                        <xsl:text>  </xsl:text>
                    </xsl:for-each>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:template>
    
        <xsl:template name="diffspace">
            <xsl:param name="indent" select="0" as="xs:integer"/>
            <xsl:param name="primary" select="false()"/>
            <xsl:for-each select="0 to $indent">
                <xsl:choose>
                    <xsl:when test="$primary">
                        <xsl:text>++</xsl:text>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:text>--</xsl:text>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each>
        </xsl:template>
    
        <!-- just an "enum" for deciding whether to group adjacent diffs -->
        <xsl:function name="util:diff-type" as="xs:integer">
            <xsl:param name="construct"/>
            <xsl:sequence select="if ($construct/self::primary:*[@*]) then 1 else
                                  if ($construct/self::control:*[@*]) then 2 else
                                  if ($construct/self::primary:*) then 3 else
                                  if ($construct/self::control:*) then 4 else
                                  if ($construct) then 5 else 0"/>
        </xsl:function>
    
        <!-- end PRINTERS -->
    
    </xsl:stylesheet>
    

    考虑这个示例输入,基于您的:

    <test>
        <Node>
            <Child name="Alpha"/>
            <Child name="Beta"/>
            <Child name="Charlie"/>
        </Node>
        <Node>
            <Child name="Beta"/>
            <Child name="Charlie"/>
            <Child name="Alpha"/>
        </Node>
    </test>
    

    在样式表保持不变的情况下,以下是应用于示例时的输出:

    <Node>
      <Child
    ++++++++<!-- ... -->
    +       name="Alpha"
    --------<!-- ... -->
    -       name="Beta">
      </Child>
      <Child
    ++++++++<!-- ... -->
    +       name="Beta"
    --------<!-- ... -->
    -       name="Charlie">
      </Child>
      <Child
    ++++++++<!-- ... -->
    +       name="Charlie"
    --------<!-- ... -->
    -       name="Alpha">
      </Child>
    </Node>
    

    但是,如果添加此自定义模板:

    <xsl:template match="Child" mode="find-match" as="element()?">
        <xsl:param name="candidates" as="element()*"/>
        <xsl:sequence select="$candidates[@name = current()/@name][1]"/>
    </xsl:template>
    

    Child 基于its的元素 @name 属性,则不会得到任何输出(表示没有差异)。

        7
  •  0
  •   R. Tanguy    8 年前

    下面是一个使用SWI Prolog的diff解决方案

    :- use_module(library(xpath)).
    load_trees(XmlRoot1, XmlRoot2) :-
        load_xml('./xml_source_1.xml', XmlRoot1, _),
        load_xml('./xml_source_2.xml', XmlRoot2, _).
    
    find_differences(Reference, Root1, Root2) :-
        xpath(Root1, //'Child'(@name=Name), Node),
        not(xpath(Root2, //'Child'(@name=Name), Node)),
        writeln([Reference, Name, Node]).
    
    diff :-
        load_trees(Root1, Root2),
        (find_differences('1', Root1, Root2) ; find_differences('2', Root2, Root1)).
    

    Node变量上的统一执行“diff”检测。

    下面是一些示例输出:

    % file 1 and file 2 have no differences 
    ?- diff.
    false.
    
    % "Alpha" was updated  in file 2
    ?- diff.
    [1,Alpha,element(Child,[name=Alpha],[])]
    [2,Alpha,element(Child,[name=Alpha,age=7],[])]
    false.
    
        8
  •  0
  •   Stig    7 年前

    使用C#可以完成此操作,然后将其与任何diff工具进行比较。

    public void Run()
    {
        LoadSortAndSave(@".. first file ..");
        LoadSortAndSave(@".. second file ..");
    }
    
    public void LoadSortAndSave(String path)
    {
        var xdoc = XDocument.Load(path);
        SortXml(xdoc.Root);
        File.WriteAllText(path + ".sorted", xdoc.ToString());
    }
    
    private void SortXml(XContainer parent)
    {
        var elements = parent.Elements()
            .OrderBy(e => e.Name.LocalName)
            .ToArray();
    
        Array.ForEach(elements, e => e.Remove());
    
        foreach (var element in elements)
        {
            parent.Add(element);
            SortXml(element);
        }
    }
    
        9
  •  0
  •   Vikas Tandon    7 年前

    为此编写了一个简单的java程序。在HashMap中存储两个要比较的XML,key作为元素的XPath(包括元素的文本值),value作为该元素的出现次数。然后比较键集和值的两个HashMap。

    /** *创建具有文本值且无嵌套节点的元素映射。
    *这里,映射的键是元素的XPATH和元素的文本值连接在一起,元素的值是该元素的出现次数。
    * *@param xmlContent *@抛出异常

    private static Map<String, Long> getMapOfElementsOfXML(String xmlContent)
    
            throws ParserConfigurationException, SAXException, IOException {
    
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    
        dbf.setValidating(false);
    
        DocumentBuilder db = dbf.newDocumentBuilder();
    
        Document doc1 = db.parse(new ByteArrayInputStream(xmlContent.getBytes()));
    
        NodeList entries = doc1.getElementsByTagName("*");
    
        Map<String, Long> mapElements = new HashMap<>();
    
        for (int i = 0; i < entries.getLength(); i++) {
    
            Element element = (Element) entries.item(i);
    
            if (element.getChildNodes().getLength() == 1&&element.getTextContent()!=null) {
    
                final String elementWithXPathAndValue = getXPath(element.getParentNode())
    
                        + "/"
    
                        + element.getParentNode().getNodeName()
    
                        + "/"
    
                        + element.getTagName()
    
                        + "/"
    
                        + element.getTextContent();
    
                Long countValue = mapElements.get(elementWithXPathAndValue);
    
                if (countValue == null) {
    
                    countValue = Long.valueOf(0l);
    
                } else {
    
                    ++countValue;
    
                }
    
                mapElements.put(elementWithXPathAndValue, countValue);
    
            }
    
        }
    
        return mapElements;
    
    }
    
    static String getXPath(Node node) {
    
        Node parent = node.getParentNode();
    
        if (parent == null) {
    
            return "";
    
        }
    
        return getXPath(parent) + "/" + parent.getNodeName();
    
    }
    

    完整的程序在这里 https://comparetwoxmlsignoringstanzaordering.blogspot.com/2018/12/java-program-to-compare-two-xmls.html

        10
  •  0
  •   Bigmwaj    5 年前

    1. 创建github帐户
    2. 在git帐户中创建git存储库
    3. 签出该存储库
    4. 添加要比较的文件的另一面
    5. 将内容推送到服务器
    6. 用保留边更改源
    7. 将您的内容与任何源文件进行比较
        11
  •  0
  •   Jerry    5 年前
        12
  •  -1
  •   FrankS101    9 年前
    /**
         * @author sdiallo
         * @since 2017-01-16
         * <p>
         * Compare the content of two XML file
         * </p>
         * <ul>
         * <li>Ignore the white space</li>
         * <li>Ignore the attribute order</li>
         * <li>Ignore the comment</li>
         * <li>Ignore Sequence child nodes are not the same</li>
         * <ul>
         * 
         * @param String XML
         *            first Content to be compared
         * @param String XML
         *            second Content to be compared
         * @return List the differences computed between the two files
         *         <ul>
         *         <li>null means the files are equal</li>         
         *         <li>elsewhere the files are different</li>
         *         <ul>
         * */
        public static List buildDiffXMLs(String xmlExpected, String xmlGenerated) {
            List<?> differencesList = null;
    
        XMLUnit.setIgnoreAttributeOrder(true);
        XMLUnit.setIgnoreComments(true);
        XMLUnit.setIgnoreWhitespace(true);
    
        try {
            DetailedDiff diff = new DetailedDiff(XMLUnit.compareXML(
                    xmlExpected, xmlGenerated));
    
            // Two documents are considered to be "similar" if they contain the
            // same elements and attributes regardless of order.
            if ( !diff.identical() && !diff.similar()) {
                differencesList = diff.getAllDifferences();
            }// end if
    
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    
        return differencesList;
    }// buildDiffXMLs
    
        13
  •  -2
  •   Liam Joshua    9 年前

    作为一种(非常)快速和肮脏的方法,我在紧要关头这样做了:

    1. 打开Excel
    2. 将文件1粘贴到列A中,每行一行。将范围命名为“FILE1”
    3. 将文件2粘贴到B列中,每行一行。将范围命名为“FILE2”
    4. 在C1中,输入公式:

      =IF(ISERROR(VLOOKUP(B1,FILE1,1,FALSE)),"DIFF","")
      
    5. =IF(ISERROR(VLOOKUP(A1,FILE2,1,FALSE)),"DIFF","")
      
    6. 将C列和D列填入文件的底部。

    这将高亮显示一个文件中出现的任何行,而不是另一个文件中出现的任何行。它一点也不整洁,但有时你只需要利用现有的东西就行了。

    推荐文章