Вопрос по xml, c# – Сравнить фрагменты XML и вернуть различия

7

У меня есть список аудита, полный сериализованных объектов, и я хотел бы сравнить их и вернуть список различий. «Сравнить» Я имею в виду, что я хочу вернуть, где текст для элемента изменился или где был добавлен узел (поэтому его нет в Xml1, но в Xml2 - это не произойдет наоборот)

Образец XML:

<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>

Пространства имен и имена / регистр тегов не изменятся. Все, что может измениться в этом примере, это значения между тегами и количество «CourseHotelLink» (его сериализованный список).

Конечный результат, который мне нужен, это список того, какой узел изменился - старое значение и новое значение.

Каков наилучший вариант для сравнения? Я использую .Net 4.0, поэтому вариант linq. Мне нужно уметь сравнивать, не зная имена всех узлов, хотя я буду сравнивать только два объекта одного типа. Я пытался использовать следующий код, но мне не удается адаптировать его для выбора изменений в тексте, а также дополнительных узлов.

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);
        }
    } 
}

Скорее всего, мои попытки написания кода находятся далеко, и есть гораздо лучший способ сделать это, любые предложения приветствуются!

РЕДАКТИРОВАТЬ добавить: В итоге я использовал MS Xml Diff Tool, следующий код выдает большой список HTML-таблиц двух узлов xml, различия в которых выделены зеленым цветом. Таким образом, можно (хотя и безумно) создать html, а затем отсортировать его, чтобы найти текст «lightgreen». (выделенное значение), затем выполните некоторые строковые формирования, чтобы отобразить только измененный дочерний узел.

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();
Я еще не разобрался, как заставить MS Diff и Patch получать строки XML - мой XML исходит из базы данных, и я не хочу создавать файлы каждый раз, когда я хочу его использовать ... Может быть, я сам плотный. UglyTeapot
Посмотрите на этот пост:stackoverflow.com/questions/167946/… Adriano Repetti
Вам не нужно создавать файлы, он идет со многими перегрузками для сравнения файлов, XmlTextReader или XmlNode Adriano Repetti
Фрагмент из вашего примера является допустимым XML. Если это не так (и это не просто исправить), то любое сравнение может бытьvery сложно. Я думаю, что сериализованный XML всегда действителен, поэтому он может бытьencoding вы использовали, чтобы сохранить эти файлы для вашего теста. Adriano Repetti
Любые попытки использования XmlReaders заканчиваются ошибкой XmlException: данные на корневом уровне недействительны. Строка 1, позиция 1. ', так что я предполагаю, что сериализованные объекты не являются очень допустимым XML. Следовательно, пытаясь найти решение, которое не связано с MS Patch и Diff! Я знаю, что это нетривиально, я надеялся, что наложение на него достаточных ограничений сделает это проще! Или я должен продолжать бороться с инструментом MS? UglyTeapot

Ваш Ответ

1   ответ
7

Использование XMlDiff - это путь, чтобы доказать это здесь с некоторым рабочим кодом. Я использую ваш XML. Если XML отличается (или недействителен), это может не сработать.

Оригинал:

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>";

РазныеId значение в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>";

Легкий способ создания читателей (изменить наXDocument если нужно):

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

Подготовьте автора результатов:

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

Сделайте разницу:

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

result сейчасXDocument который содержит краткое изложение различий:

<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>
Не забудьте принять ответ, если он отвечает на первоначальный вопрос :-) Существует множество информации о том, как интерпретировать возвращение изxmldiff.
Принято, спасибо! И .. есть примеры того, как интерпретировать диаграммы, чтобы показать только различия? Мой слабый гугл-фу ничего не находит UglyTeapot
Попробуйте другой вопрос и ссылку здесь, чтобы я мог видеть. Лучше всего оформить это индивидуально.
Продолжение здесь:stackoverflow.com/questions/10530381/… UglyTeapot
Это работает, спасибо! Поэтому мне просто нужно проанализировать диаграмму, чтобы она могла отображать такие вещи, как «CourseBookings Id is 0, теперь 1», что должно быть весело! UglyTeapot

Похожие вопросы