gpt4 book ai didi

c# - 在 C# 中寻找高性能的 XyDiff 端口(带有 XID 的 XML 差异补丁)

转载 作者:太空宇宙 更新时间:2023-11-03 11:21:06 25 4
gpt4 key购买 nike

我将一些数据存储为 XML,并将用户的更改存储为与原始 XML 的差异,因此可以在运行时为用户数据打补丁。

原始 xml 的示例(仅部分):

<module  id="">
<title id="">
...
</title>
<actions>
...
</actions>
<zones id="" selected="right">
<zone id="" key="right" name="Right" />
</zones>
</module>

用户差异示例(用户将 selected 的值从右更改为左):

<xd:xmldiff version="1.0" srcDocHash="" 
options="IgnoreChildOrder IgnoreNamespaces IgnorePrefixes IgnoreSrcValidation "
fragments="no"
xmlns:xd="http://schemas.microsoft.com/xmltools/2002/xmldiff">
<xd:node match="1">
<xd:node match="3">
<xd:change match="@selected">left</xd:change>
</xd:node>
</xd:node>
</xd:xmldiff>

问题是,补丁会查找 XML 节点的顺序。如果顺序发生变化,则无法再应用 diff,甚至更糟的是,它会被错误地应用。所以我更喜欢用 XID 打补丁。有谁知道用于 XyDiff 的 C# 的高性能库或算法?

最佳答案

我们现在开发了自己的解决方案,效果很好。

我们做了什么:

  • 确保原始文件中的每个 xml 节点都有一个唯一的 id(没有无论在哪个层面)
  • 为用户更改生成一个平面 xml 补丁,只保存每个变化节点的变化(没有层次结构)
  • 如果用户改变了一个值,在patch xml中写一个xmlpatch节点属性targetid指向原始节点的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 中的更改。我们通过 targetid 获取原始节点并覆盖属性和值。

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

关于c# - 在 C# 中寻找高性能的 XyDiff 端口(带有 XID 的 XML 差异补丁),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10983718/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com