Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
正在C#中寻找性能良好的XyDiff端口(使用XID的XML差异修补程序)_C#_Xml_Xmldiff - Fatal编程技术网

正在C#中寻找性能良好的XyDiff端口(使用XID的XML差异修补程序)

正在C#中寻找性能良好的XyDiff端口(使用XID的XML差异修补程序),c#,xml,xmldiff,C#,Xml,Xmldiff,我将一些数据存储为XML,将用户的更改存储为与原始XML不同的内容,因此可以在运行时修补用户的数据 原始xml的示例(仅部分): ... ... 用户差异示例(用户从右到左更改了所选的值): 左边 问题是,修补程序查找XML节点的顺序。如果订单发生变化,则无法再应用差异,甚至更糟,它将被错误地应用。所以我更喜欢用XID打补丁。 有人知道C#的性能库或算法吗?我们现在开发了自己的解决方案,效果很好 我们做了什么: 确保原始文件中的每个xml节点都有一个唯一的id(no (在哪个级别上的问

我将一些数据存储为XML,将用户的更改存储为与原始XML不同的内容,因此可以在运行时修补用户的数据

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


...
...
用户差异示例(用户从右到左更改了所选的值):


左边
问题是,修补程序查找XML节点的顺序。如果订单发生变化,则无法再应用差异,甚至更糟,它将被错误地应用。所以我更喜欢用XID打补丁。
有人知道C#的性能库或算法吗?

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

我们做了什么:

  • 确保原始文件中的每个xml节点都有一个唯一的id(no (在哪个级别上的问题)
  • 为用户更改生成一个仅保存 每个变更节点的变更(无层级结构)
  • 如果用户更改了值,请在修补程序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中的更改打回补丁。我们通过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;
}

让我直截了当地说:您当前正在使用XyDiff比较两个XML文件,它生成所示的输出。您对这个输出不满意,因为它依赖于有序的XML结构。您现在正在寻找一个diff工具或算法,该工具或算法提供更改节点的ID以及新值?到目前为止这是正确的吗?是的,正确。然后,匹配将显示Xml节点的Guid。。。但我们目前正在使用XmlDiffPatch。您使用的是哪个版本的C#?如果它是>C#2.0,那么Linq2Xml可能是一个选项。这需要您自己编写比较。下面的问题:在比较之后,原始文件的顺序是否会改变,或者用户编辑的文件的顺序是否与原始文件不同?如果是后者,则可以在创建差异时指定
xmldifoptions.IgnoreChildOrder
。有关详细信息,请参阅。
<patch>
  <xmlpatch sortorder="10" visible="true" targetId="{Guid-x}" />
  <xmlpatch selected="left" targetId="{Guid-y}" />
  <xmlpatch targetId="{Guid-z}">true</xmlpatch>
</patch>
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);
    }
}
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;
}