我有两个由我无法控制的应用程序生成的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
处理的方法似乎更多的工作。
答案 0 :(得分:3)
如果文件变得非常大,这将是非常低效的,但这是你可以用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" );
答案 1 :(得分:2)
不确定效率,但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!");
}
添加使用条款留作练习:)
还有另一个例子here,但它在VB中具有更多的XML功能。
我还认为通过连接两组XML数据的查询可以做一些非常优雅的事情,生成一个包含XElement和它需要的值(或值)的动态类型列表要更新。但是我已经有足够的乐趣(花了足够的时间)这个已经有一个晚上了
答案 2 :(得分:2)
使用连接将Linq转换为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");
答案 3 :(得分:0)
XmlDocument对于此过程来说是理想的,并且远远少于您建议的其他方法。如果将LARGE Xml文件用作XmlDocument将整个文档加载到内存中,您可能需要查看其他方法来解决此问题!
无论如何,XmlDocument方法将类似于:
我知道我告诉你要做什么,但我可能不会清楚地解释它。我可以在30分钟内完成这个程序的非常粗略的版本,我只有大约一年的c#经验。