Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/13.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/13.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# 将XML文件与更改列表合并_C#_Xml_Merge - Fatal编程技术网

C# 将XML文件与更改列表合并

C# 将XML文件与更改列表合并,c#,xml,merge,C#,Xml,Merge,我有两个XML文件,它们是由另一个我无法控制的应用程序生成的。第一个是设置文件,第二个是应应用于第一个文件的更改列表 主设置文件: <?xml version="1.0"?> <preset> <var id="9" opt="0" val="6666666"/> <var id="9" opt="1" val="10000000"/> <var id="9" opt="2" val="10000000"/> <v

我有两个XML文件,它们是由另一个我无法控制的应用程序生成的。第一个是设置文件,第二个是应应用于第一个文件的更改列表

主设置文件:

<?xml version="1.0"?>
<preset>
  <var id="9" opt="0" val="6666666"/>
  <var id="9" opt="1" val="10000000"/>
  <var id="9" opt="2" val="10000000"/>
  <var id="9" opt="3" val="10000000"/>
  <var id="9" opt="4" val="0"/>
  <var id="10" opt="0" val="4"/>
  <var id="11" opt="0" val="0"/>
  <var id="15" opt="0" val="75"/>
  <var id="22" opt="0" val="0,0,127,516" type="rect(l,t,r,b)"/>
  <var id="23" opt="0" val="27,18,92,66" type="rect(l,t,r,b)"/>
  <var id="24" opt="0" val="320"/>
  ... Skip 300 lines ...
</preset>
下面是一个变化的例子:

<?xml version="1.0"?>
<preset>
  <var id="15" opt="0" val="425"/>
  <var id="22" opt="0" val="0,0,127,776" type="rect(l,t,r,b)"/>
  <var id="26" opt="0" val="147"/>
  <var id="27" opt="0" val="147"/>
  <var id="109" opt="1" val="7"/>
  <var id="126" opt="0" val="6,85,85,59" type="crv(t,m,b,vm)"/>
  <var id="157" opt="0" val="1"/>
  ... Skip 10 lines ...
</preset>
每个变量都有一个ID和一个适用于该ID的优化。基本上,我希望用变更文件中的版本替换id=和opt=相同的行。在上面的示例中,id=15 opt=0的值将从75更改为425


在C语言中有没有干净的方法?乍一看,以文本形式阅读并使用find-replace类型的方法逐步完成更改似乎是最干净的。将其作为XmlDocument处理的方法似乎要做更多的工作。

如果文件变得很大,这将是非常低效的,但这就是使用XmlDocuments的方法:

XmlDocument main = new XmlDocument();
main.Load( "main.xml" );

XmlDocument changes = new XmlDocument();
changes.Load( "changes.xml" );

foreach ( XmlNode mainNode in main.SelectNodes( "preset/var" ) )
{
    string mainId = mainNode.Attributes[ "id" ].Value;
    string mainOpt = mainNode.Attributes[ "opt" ].Value;

    foreach ( XmlNode changeNode in changes.SelectNodes( "preset/var" ) )
    {
        if ( mainId == changeNode.Attributes[ "id" ].Value &&
            mainOpt == changeNode.Attributes[ "opt" ].Value )
        {
            mainNode.Attributes[ "val" ].Value = changeNode.Attributes[ "val" ].Value;
        }
    }
}

// save the updated main document
main.Save( "updated_main.xml" );

XmlDocument非常适合这个过程,并且比您建议的其他方法工作量小得多。如果您使用大型Xml文件作为XmlDocument将整个文档加载到内存中,那么您可能需要查看其他方法来实现这一点

无论如何,XmlDocument方法类似于:

将这两个文件加载到各自的XmlDocument对象中。 迭代更改文件XmlDocument对象中的var节点列表,foreach one在原始文件XmlDocument对象上运行xpath查询,以在找到编辑需要在节点中编辑的属性时,使用原始文件XmlDocument对象上的SelectSingleNode方法搜索具有匹配id的节点。 完成所有编辑后保存文件。
我知道我告诉你要做的事很管用,但我可能没有解释清楚。我可以在30分钟内完成这个程序的一个非常粗略的版本,而且我在c语言方面只有大约一年的经验。

不确定效率,但这对于Linq到XML来说很简单-下面的内容有点粗略-但是记住非常出色的LinqPAD将允许您运行程序。。。随函附上完成此项工作的完整代码:

void Main()
{
    XDocument settingsXML = XDocument.Load(@"c:\temp\settings.xml");
    XDocument updateXML = XDocument.Load(@"c:\temp\updates.xml");

    Console.WriteLine("Processing");

    // Loop through the updates
    foreach(XElement update in updateXML.Element("preset").Elements("var"))
    {    
        // Find the element to update    
        XElement settingsElement = 
            (from s in settingsXML.Element("preset").Elements("var")
             where s.Attribute("id").Value == update.Attribute("id").Value &&
                   s.Attribute("opt").Value == update.Attribute("opt").Value
             select s).FirstOrDefault();    
        if (settingsElement != null)    
        {      
            settingsElement.Attribute("val").Value = update.Attribute("val").Value;    
            // Handling for additional attributes here
        }    
        else    
        {   
            // not found handling    
            Console.WriteLine("Not found {0},{1}", update.Attribute("id").Value,
                                                   update.Attribute("opt").Value);
        }
    }
    Console.WriteLine("Saving");
    settingsXML.Save(@"c:\temp\updatedSettings.xml");
    Console.WriteLine("Finis!");
}
添加using子句作为练习:

还有另一个例子,但它是在VB中,它在XML方面有更多的功能


我还认为,通过将两组XML数据连接起来,生成一个动态类型列表,其中包含一个XElement和一个或多个需要更新的值,可以做一些非常优雅的事情。但是我已经玩得很开心了,花了足够的时间在这本书上已经有一个晚上了。

在Linq to XML中使用连接将文档关联在一起的示例。首先,我选择两个属性上匹配的元素,然后从更改文件中将它们更新为新值

XDocument main = XDocument.Load("XMLFile1.xml");
XDocument changes = XDocument.Load("XMLFile2.xml");

var merge = from entry in main.Descendants("preset").Descendants("var")
            join change in changes.Descendants("preset").Descendants("var")
            on 
               new {a=entry.Attribute("id").Value, b=entry.Attribute("opt").Value}
            equals 
               new {a=change.Attribute("id").Value, b=change.Attribute("opt").Value}
            select new
            {
               Element = entry,
               newValue = change.Attribute("val").Value                       
            };

            merge.ToList().ForEach(i => i.Element.Attribute("val").Value = i.newValue);

            main.Save("XMLFile3.xml");

这是一次性的事情,还是你必须定期做的事情?定期。基本上,用户会保存SDK自动生成的更改,我会将它们与原始设置合并。这样做效果很好。作为一个控制台应用程序,584行XML文件的总执行时间为21ms,其中包含20个更改,这对于如何使用该文件非常有用。谢谢我很想知道这个解决方案在性能上与上面的强力循环公认的答案相比如何。