2012-05-07 62 views
5

Mam listę kontroli pełną serializowanych obiektów i chciałbym je porównać i zwrócić listę różnic. Przez "porównać" mam na myśli to, że chcę powrócić tam, gdzie zmienił się tekst elementu, lub gdzie został dodany węzeł (więc nie jest w Xml1, ale jest w Xml2 - nie stanie się odwrotnie)Porównywanie fragmentów XML i różnic zwracanych

xml

Próbka:

<HotelBookingView xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Id>119</Id> 
    <RoomId>1</RoomId> 
    <ChangeRequested>false</ChangeRequested> 
    <CourseBookings>  
    <CourseHotelLink> 
     <Id>0</Id> 
    </CourseHotelLink> 
</CourseBookings> 
</HotelBookingView> 

przestrzeni nazw i nazwy/przypadek znaczniki nie ulegnie zmianie. Wszystko, co można zmienić w tym przykładzie, to wartości między tagami i liczba "CourseHotelLink" (lista zserializowana).

Końcowy wynik, który chciałbym, to lista węzłów uległa zmianie - stara wartość i nowa wartość.

Jaki jest najlepszy sposób ich porównania? Używam .Net 4.0, więc linq jest opcją. Muszę umieć dokonać porównania bez znajomości nazw wszystkich węzłów - choć porównuję tylko dwa obiekty tego samego typu. Próbowałem użyć następującego kodu, ale nie mogę go dostosować, aby wykryć zmiany w tekście, a także dodatkowe węzły.

XmlDocument Xml1 = new XmlDocument(); 
XmlDocument Xml2 = new XmlDocument(); 
Xml1.LoadXml(list[1].Changes); 
Xml2.LoadXml(list[2].Changes); 
foreach (XmlNode chNode in Xml2.ChildNodes) 
{ 
    CompareLower(chNode); 
} 

protected void CompareLower(XmlNode aNode) 
{ 
    foreach (XmlNode chlNode in aNode.ChildNodes) 
    { 
     string Path = CreatePath(chlNode); 
     if (chlNode.Name == "#text") 
     { 
      //all my efforts at comparing text have failed 
      continue; 
     } 
     if (Xml1.SelectNodes(Path).Count == 0) 
     { 
      XmlNode TempNode = Xml1.ImportNode(chlNode, true); 
      //node didn't used to exist, this works- though doesn't return values 
      str = str + "New Node: " + TempNode.Name + ": " + TempNode.Value; 
     } 
     else 
     { 
      CompareLower(chlNode); 
     } 
    } 
} 

Jest prawdopodobne, moje próby kodu są mile off i jest znacznie lepszy sposób to zrobić, wszelkie sugestie mile widziane!

EDITTED, aby dodać: Skończyło się na użyciu narzędzia MS Xml Diff, poniższy kod tworzy dużą tabelę html z dwoma węzłami xml, z różnicami zaznaczonymi na zielono. Więc jest to możliwe (choć szalone) do wytworzenia html, a następnie posortuj go, aby znaleźć tekst "lightgreen" (podświetlona wartość), następnie wykonaj kilka formacji smyczkowych, aby wyświetlić tylko zmieniony węzeł-dziecko.

var node1 = XElement.Parse("Xml string 1 here").CreateReader(); 
var node2 = XElement.Parse("Xml string 2 here").CreateReader(); 

MemoryStream diffgram = new MemoryStream(); 
XmlTextWriter diffgramWriter = new XmlTextWriter(new StreamWriter(diffgram)); 

XmlDiff xmlDiff = new XmlDiff(XmlDiffOptions.IgnoreChildOrder); 
xmlDiff.Algorithm = XmlDiffAlgorithm.Fast; 
xmlDiff.Compare(node1, node2,diffgramWriter); 

diffgram.Seek(0, SeekOrigin.Begin); 
XmlDiffView xmlDiffView = new Microsoft.XmlDiffPatch.XmlDiffView(); 
StringBuilder sb = new StringBuilder(); 
TextWriter resultHtml = new StringWriter(sb); 
xmlDiffView.Load("Xml string 1", new XmlTextReader(diffgram)); 

xmlDiffView.GetHtml(resultHtml); 
resultHtml.Close(); 
+1

spojrzeć na tym stanowisku: http://stackoverflow.com/questions/167946/how-would-you-compare-dwa-xml-dokumenty –

+0

Jeszcze nie opracowałem, jak uzyskać MS Diff i Patch do pobierania łańcuchów XML - mój XML pochodzi z bazy danych i nie chcę aby tworzyć pliki za każdym razem, gdy chcę o użyj go ... Może po prostu być gęsty. – UglyTeapot

+0

Nie trzeba tworzyć plików, występuje wiele przeciążeń w celu porównania plików, XmlTextReader lub XmlNode –

Odpowiedz

7

Używanie XMlDiff jest sposobem na udanie się - aby udowodnić, że działa kod. Używam twojego XML. Jeśli XML jest inny (lub nieprawidłowy), może nie działać.

oryginalny:

var xml1 = @"<HotelBookingView xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> 
<Id>119</Id> 
<RoomId>1</RoomId> 
<ChangeRequested>false</ChangeRequested> 
<CourseBookings>  
    <CourseHotelLink> 
    <Id>0</Id> 
    </CourseHotelLink> 
</CourseBookings> 
</HotelBookingView>"; 

Different Id wartość CourseBookings:

var xml2 = @"<HotelBookingView xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> 
<Id>119</Id> 
<RoomId>1</RoomId> 
<ChangeRequested>false</ChangeRequested> 
<CourseBookings>  
    <CourseHotelLink> 
    <Id>1</Id> 
    </CourseHotelLink> 
</CourseBookings> 
</HotelBookingView>"; 

Niska sposób wysiłek tworzenia czytelników (zmiany XDocument w razie potrzeby):

var node1 = XElement.Parse(xml1).CreateReader(); 
var node2 = XElement.Parse(xml2).CreateReader(); 

Przygotuj wynik pisarz:

var result = new XDocument(); 
var writer = result.CreateWriter(); 

Wykonaj Diff:

var diff = new Microsoft.XmlDiffPatch.XmlDiff();  
diff.Compare(node1, node2, writer); 
writer.Flush(); writer.Close(); 

result jest teraz XDocument, który zawiera podsumowanie różnic:

<xd:xmldiff version="1.0" srcDocHash="14506386314386767543" options="None" fragments="no" xmlns:xd="http://schemas.microsoft.com/xmltools/2002/xmldiff"> 
    <xd:node match="1"> 
    <xd:node match="4"> 
     <xd:node match="1"> 
     <xd:node match="1"> 
      <xd:change match="1">1</xd:change> 
     </xd:node> 
     </xd:node> 
    </xd:node> 
    </xd:node> 
</xd:xmldiff> 
+0

To działa, dziękuję! Po prostu potrzebuję parsować diffgram, aby móc wyświetlać takie rzeczy jak "CourseBookings Id był 0, teraz 1", co powinno być zabawą! – UglyTeapot

+0

Nie zapomnij przyjąć odpowiedzi na oryginalne pytanie :-) Istnieje wiele informacji na temat interpretacji zwrotu z 'xmldiff'. – yamen

+0

Zaakceptowany, dziękuję! I .. są przykłady, jak interpretować diffgramy, aby pokazać tylko różnice? Mój słaby google-fu nic nie znajduje. – UglyTeapot

Powiązane problemy