Files
Orchard/src/Orchard.Web/Modules/Orchard.AuditTrail/Services/DiffGramAnalyzer.cs

112 lines
5.7 KiB
C#
Raw Normal View History

2014-06-02 15:12:56 +02:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using Microsoft.XmlDiffPatch;
using Orchard.AuditTrail.Services.Models;
2014-06-02 15:12:56 +02:00
namespace Orchard.AuditTrail.Services {
2014-06-02 15:12:56 +02:00
public class DiffGramAnalyzer : IDiffGramAnalyzer {
public XElement GenerateDiffGram(XElement element1, XElement element2) {
using (var node1Reader = element1.CreateReader())
2014-06-02 15:12:56 +02:00
using (var node2Reader = element2.CreateReader()) {
var result = new XDocument();
using (var writer = result.CreateWriter()) {
var diff = new XmlDiff(XmlDiffOptions.IgnoreChildOrder | XmlDiffOptions.IgnoreWhitespace | XmlDiffOptions.IgnoreComments | XmlDiffOptions.IgnoreXmlDecl);
2014-06-02 15:12:56 +02:00
diff.Compare(node1Reader, node2Reader, writer);
writer.Flush();
writer.Close();
}
return result.Root;
}
}
public IEnumerable<DiffNode> Analyze(XElement original, XElement diffGram) {
var stack = new Stack<XElement>();
stack.Push(new XElement("original", original));
using (var reader = diffGram.CreateReader()) {
while (!reader.EOF) {
2014-06-02 20:12:18 +02:00
var readNext = true;
2014-06-02 15:12:56 +02:00
switch (reader.NodeType) {
case XmlNodeType.Element:
var match = reader.GetAttribute("match");
var isAttributeChange = match != null && match.StartsWith("@");
var index = match == null || isAttributeChange ? default(int?) : Int32.Parse(match) - 1;
var diffType = reader.LocalName;
var currentElement = stack.Peek();
if (currentElement.HasElements && index != null) {
var sourceElement = currentElement.Elements().ElementAt(index.Value);
stack.Push(sourceElement);
}
if (diffType != "node") {
switch (diffType) {
case "change":
if (isAttributeChange) {
var attributeName = match.Substring(1);
var originalValue = currentElement.Attribute(attributeName).Value;
var currentValue = reader.ReadElementContentAsString();
2014-06-02 20:12:18 +02:00
readNext = false;
2014-06-02 15:12:56 +02:00
yield return
new DiffNode {
Type = DiffType.Change,
2014-07-01 11:56:42 -07:00
Context = BuildContextName(stack, attributeName),
2014-06-02 15:12:56 +02:00
Previous = originalValue,
Current = currentValue
};
}
else {
var elementName = currentElement.Name.ToString();
2014-06-02 15:12:56 +02:00
var originalContent = currentElement.Value;
var currentContent = reader.ReadElementContentAsString();
2014-06-02 20:12:18 +02:00
readNext = false;
2014-06-02 15:12:56 +02:00
yield return
new DiffNode {
Type = DiffType.Change,
Context = BuildContextName(stack, elementName),
2014-06-02 15:12:56 +02:00
Previous = originalContent,
Current = currentContent
};
}
break;
case "add":
var nodeName = reader.GetAttribute("name");
var addedContent = default(string);
reader.Read();
if (reader.NodeType != XmlNodeType.EndElement) {
nodeName = reader.Name;
addedContent = reader.ReadOuterXml();
}
yield return
new DiffNode {
Type = DiffType.Addition,
Context = BuildContextName(stack, nodeName),
Current = addedContent
};
2014-06-02 15:12:56 +02:00
break;
}
}
break;
case XmlNodeType.EndElement:
if(stack.Any())
stack.Pop();
2014-06-02 15:12:56 +02:00
break;
}
2014-06-02 20:12:18 +02:00
if (readNext)
2014-06-02 15:12:56 +02:00
reader.Read();
}
}
}
2014-07-01 11:56:42 -07:00
private string BuildContextName(IEnumerable<XElement> stack, string nodeName) {
return String.Format("{0}/{1}", String.Join("/", stack.Reverse().Skip(1).Select(x => x.Name)), nodeName);
2014-07-01 11:56:42 -07:00
}
2014-06-02 15:12:56 +02:00
}
}