我們現在開發了我們自己的解決方案,工作正常。
我們做了什麼:
- 確保在原文件中的每個XML節點都有一個唯一的ID(不 無論哪個級別)
- 生成用於不僅節省了用戶的變化平坦的XML補丁每個變化節點的 變化(無級結構)
- 如果用戶改變一個值,寫在補丁XML 與屬性的xmlpatch節點目標ID指向原始節點的ID
- 如果用戶改變的屬性,寫入與新 值到xmlpatch節點
- 如果用戶改變一個值的屬性,該值寫入到xmlpatch節點
的XML補丁看起來如下:
<patch>
<xmlpatch sortorder="10" visible="true" targetId="{Guid-x}" />
<xmlpatch selected="left" targetId="{Guid-y}" />
<xmlpatch targetId="{Guid-z}">true</xmlpatch>
</patch>
生成補丁xml的代碼非常簡單。我們通過所有屬性循環遍歷所有xml節點和每個節點。如果節點的屬性或值與原始節點不同,我們將生成帶有屬性或值的修補節點。請注意,代碼寫在一個晚上;)
public static XDocument GenerateDiffGram(XDocument allUserDocument, XDocument runtimeDocument)
{
XDocument diffDocument = new XDocument();
XElement root = new XElement("patch");
AddElements(root, runtimeDocument, allUserDocument.Root);
diffDocument.Add(root);
return diffDocument;
}
private static void AddElements(XElement rootPatch, XDocument runtimeDocument, XElement allUserElement)
{
XElement patchElem = null;
if (allUserElement.Attribute("id") != null
&& !string.IsNullOrWhiteSpace(allUserElement.Attribute("id").Value))
{
// find runtime element by id
XElement runtimeElement = (from e in runtimeDocument.Descendants(allUserElement.Name)
where e.Attribute("id") != null
&& e.Attribute("id").Value.Equals(allUserElement.Attribute("id").Value)
select e).FirstOrDefault();
// create new patch node
patchElem = new XElement("xmlpatch");
// check for changed attributes
foreach (var allUserAttribute in allUserElement.Attributes())
{
XAttribute runtimeAttribute = runtimeElement.Attribute(allUserAttribute.Name);
if (!allUserAttribute.Value.Equals(runtimeAttribute.Value))
{
patchElem.SetAttributeValue(allUserAttribute.Name, runtimeAttribute.Value);
}
}
// check for changed value
if (!allUserElement.HasElements
&& !allUserElement.Value.Equals(runtimeElement.Value))
{
patchElem.Value = runtimeElement.Value;
}
}
// loop through all children to find changed values
foreach (var childElement in allUserElement.Elements())
{
AddElements(rootPatch, runtimeDocument, childElement);
}
// add node for changed value
if (patchElem != null
&& (patchElem.HasAttributes
|| !string.IsNullOrEmpty(patchElem.Value)))
{
patchElem.SetAttributeValue("targetId", allUserElement.Attribute("id").Value);
rootPatch.AddFirst(patchElem);
}
}
在運行時,我們打補丁保存在XML補丁後面的變化。我們通過targettid創建原始節點並覆蓋屬性和值。
public static XDocument Patch(XDocument runtimeDocument, XDocument userDocument, string modulePath, string userName)
{
XDocument patchDocument = new XDocument(userDocument);
foreach (XElement element in patchDocument.Element("patch").Elements())
{
// get id of the element
string idAttribute = element.Attribute("targetId").Value;
// get element with id from allUserDocument
XElement sharedElement = (from e in runtimeDocument.Descendants()
where e.Attribute("id") != null
&& e.Attribute("id").Value.Equals(idAttribute)
select e).FirstOrDefault();
// element doesn't exist anymore. Maybe the admin has deleted the element
if (sharedElement == null)
{
// delete the element from the user patch
element.Remove();
}
else
{
// set attributes to user values
foreach (XAttribute attribute in element.Attributes())
{
if (!attribute.Name.LocalName.Equals("targetId"))
{
sharedElement.SetAttributeValue(attribute.Name, attribute.Value);
}
}
// set element value
if (!string.IsNullOrEmpty(element.Value))
{
sharedElement.Value = element.Value;
}
}
}
// user patch has changed (nodes deleted by the admin)
if (!patchDocument.ToString().Equals(userDocument.ToString()))
{
// save back the changed user patch
using (PersonalizationProvider provider = new PersonalizationProvider())
{
provider.SaveUserPersonalization(modulePath, userName, patchDocument);
}
}
return runtimeDocument;
}
讓我直截了當地看看:您目前正在使用XyDiff比較兩個XML文件,它會生成顯示的輸出。您對此輸出不滿意,因爲它依賴於有序的XML結構。您現在正在尋找一種diff工具或算法,它可以提供已更改節點的ID以及新值?目前爲止是否正確? – froeschli
是的,正確的。該匹配將顯示Xml節點的Guid。 ... –
但是,我們使用的是XmlDiffPatch的時刻。 –