UFO ET IT

두 개의 XML 문서를 어떻게 비교 하시겠습니까?

ufoet 2020. 12. 8. 20:28
반응형

두 개의 XML 문서를 어떻게 비교 하시겠습니까?


광범위한 단위 테스트를위한 기본 클래스의 일부로 C # (. NET)에서 한 XmlDocument 개체의 노드를 다른 개체와 재귀 적으로 비교하는 도우미 함수를 작성하고 있습니다. 이에 대한 몇 가지 요구 사항 :

  • 첫 번째 문서는 소스입니다 . 예를 들어 XML 문서의 모양을 지정합니다. 따라서 두 번째는 차이점을 찾고 싶은 것이며 첫 번째 문서에없는 추가 노드를 포함하지 않아야합니다 .
  • 너무 많은 중요한 차이점이 발견되면 예외를 throw해야하며 설명을 훑어 보는 사람이 쉽게 이해할 수 있어야합니다.
  • 하위 요소 순서가 중요하며 속성은 임의의 순서로있을 수 있습니다.
  • 일부 속성은 무시할 수 있습니다. 구체적으로 xsi:schemaLocation그리고 xmlns:xsi, 어느 것이 있는지 전달할 수 있기를 원합니다.
  • 네임 스페이스의 접두사는 속성과 요소 모두에서 일치해야합니다.
  • 요소 사이의 공백은 관련이 없습니다.
  • 요소는 것 중 하나 자식 요소가 InnerText 있지만 둘 다.

함께 스크랩하는 동안 누군가 이러한 코드를 작성했으며 여기에서 공유 할 수 있습니까?

제쳐두고 첫 번째 문서와 두 번째 문서를 무엇이라고 부르겠습니까? 나는 그것들을 "소스"와 "타겟"이라고 부르고 있지만 소스 가 내가 원하는 타겟되기를 바라기 때문에 잘못된 느낌이 든다 . 그렇지 않으면 예외를 던진다.


Microsoft에는 사용할 수 있는 XML diff API 가 있습니다.

비공식 NuGet : https://www.nuget.org/packages/XMLDiffPatch .


오늘이 문제에 대한보다 완전한 솔루션 목록을 검색했습니다. 곧 그중 하나를 시도해 보겠습니다.


XMLUnit 시도 하십시오 . 이 라이브러리는 Java 및 .Net 모두에서 사용할 수 있습니다.


XML 문서를 비교하는 것은 복잡합니다. 일부 도구의 경우 xmldiff 용 Google (마이크로 소프트 솔루션도 있습니다). 나는 이것을 몇 가지 방법으로 해결했습니다. XSLT를 사용하여 요소와 속성을 정렬하고 (때로는 다른 순서로 나타나기도하는데 신경도 쓰지 않았기 때문입니다) 비교하고 싶지 않은 속성을 필터링 한 다음 XML :: Diff를 사용했습니다. 또는 XML :: SemanticDiff perl 모듈 또는 모든 요소와 속성을 별도의 줄에 표시하고 결과에 Unix 명령 줄 diff를 사용하여 각 문서를 예쁘게 인쇄했습니다.


이 코드는 모든 요구 사항을 충족하지는 않지만 간단하고 단위 테스트에 사용하고 있습니다. 속성 순서는 중요하지 않지만 요소 순서는 중요합니다. 요소 내부 텍스트는 비교되지 않습니다. 속성을 비교할 때도 대소 문자를 무시했지만 쉽게 제거 할 수 있습니다.

public bool XMLCompare(XElement primary, XElement secondary)
{
    if (primary.HasAttributes) {
        if (primary.Attributes().Count() != secondary.Attributes().Count())
            return false;
        foreach (XAttribute attr in primary.Attributes()) {
            if (secondary.Attribute(attr.Name.LocalName) == null)
                return false;
            if (attr.Value.ToLower() != secondary.Attribute(attr.Name.LocalName).Value.ToLower())
                return false;
        }
    }
    if (primary.HasElements) {
        if (primary.Elements().Count() != secondary.Elements().Count())
            return false;
        for (var i = 0; i <= primary.Elements().Count() - 1; i++) {
            if (XMLCompare(primary.Elements().Skip(i).Take(1).Single(), secondary.Elements().Skip(i).Take(1).Single()) == false)
                return false;
        }
    }
    return true;
}

XML 파일을 비교하기 위해 ExamXML사용하고 있습니다. 시도해 볼 수 있습니다. 저자 A7Soft는 XML 파일 비교를위한 API도 제공합니다.


https://github.com/CameronWills/FatAntelope Microsoft XML Diff API에 대한 또 다른 대체 라이브러리입니다. 두 XML 문서의 순서없는 비교를 수행하고 최적의 일치를 생성하는 XML diffing 알고리즘이 있습니다.

여기에 설명 된 X-Diff 알고리즘의 C # 포트입니다. http://pages.cs.wisc.edu/~yuanwang/xdiff.html

면책 조항 : 내가 썼습니다 :)


이를 수행하는 또 다른 방법은 다음과 같습니다.

  1. 두 파일의 내용을 두 개의 다른 문자열로 가져옵니다.
  2. XSLT를 사용하여 문자열을 변환합니다 (모든 것을 두 개의 새 문자열로 복사합니다). 이렇게하면 요소 외부의 모든 공간이 제거됩니다. 결과적으로 두 개의 새로운 문자열이 생성됩니다.
  3. 이제 두 문자열을 서로 비교하십시오.

이것은 차이점의 정확한 위치를 제공하지 않지만 차이점이 있는지 알고 싶다면 타사 라이브러리없이 쉽게 수행 할 수 있습니다.


현재 자식 순서를 무시하기 때문에 OP와 관련이 없지만 코드 전용 솔루션을 원한다면 내가 다소 잘못 개발 한 XmlSpecificationCompare시도해 볼 수 있습니다 .


자동화 된 테스트에서 두 개의 XML 출력을 비교하기 위해 XNode.DeepEquals.

모든 하위 노드의 값을 포함하여 두 노드의 값을 비교합니다.

용법:

var xDoc1 = XDocument.Parse(xmlString1);
var xDoc2 = XDocument.Parse(xmlString2);

bool isSame = XNode.DeepEquals(xDoc1.Document, xDoc2.Document);
//Assert.IsTrue(isSame);

참조 : https://docs.microsoft.com/en-us/dotnet/api/system.xml.linq.xnode.deepequals?view=netcore-2.2


@Two Cents 답변을 기반으로 하고이 링크를 사용하여 XMLSorting 내 자신의 XmlComparer를 만들었습니다.

XML 프로그램 비교

private static bool compareXML(XmlNode node, XmlNode comparenode)
    {

        if (node.Value != comparenode.Value)
            return false;

            if (node.Attributes.Count>0)
            {
                foreach (XmlAttribute parentnodeattribute in node.Attributes)
                {
                    string parentattributename = parentnodeattribute.Name;
                    string parentattributevalue = parentnodeattribute.Value;
                    if (parentattributevalue != comparenode.Attributes[parentattributename].Value)
                    {
                        return false;
                    }

                }

            }

          if(node.HasChildNodes)
            {
            sortXML(comparenode);
            if (node.ChildNodes.Count != comparenode.ChildNodes.Count)
                return false;
            for(int i=0; i<node.ChildNodes.Count;i++)
                {

                string name = node.ChildNodes[i].LocalName;
                if (compareXML(node.ChildNodes[i], comparenode.ChildNodes[i]) == false)
                    return false;
                }

            }



        return true;
    }

XML 프로그램 정렬

 private static void sortXML(XmlNode documentElement)
    {
        int i = 1;
        SortAttributes(documentElement.Attributes);
        SortElements(documentElement);
        foreach (XmlNode childNode in documentElement.ChildNodes)
        {
            sortXML(childNode);

        }
    }



  private static void SortElements(XmlNode rootNode)
    {



            for(int j = 0; j < rootNode.ChildNodes.Count; j++) {
                for (int i = 1; i < rootNode.ChildNodes.Count; i++)
                {
                    if (String.Compare(rootNode.ChildNodes[i].Name, rootNode.ChildNodes[1 - 1].Name) < 0)
                    {
                        rootNode.InsertBefore(rootNode.ChildNodes[i], rootNode.ChildNodes[i - 1]);

                    }


                }
            }
           // Console.WriteLine(j++);


    }
 private static void SortAttributes(XmlAttributeCollection attribCol)
    {
        if (attribCol == null)
            return;
        bool changed = true;
        while (changed)
        {
            changed = false;
            for (int i = 1; i < attribCol.Count; i++)
        {
                if (String.Compare(attribCol[i].Name, attribCol[i - 1].Name) < 0)
                {
                    //Replace
                    attribCol.InsertBefore(attribCol[i], attribCol[i - 1]);
                    changed = true;

                }
            }
        }
    }

참고 URL : https://stackoverflow.com/questions/167946/how-would-you-compare-two-xml-documents

반응형