我有两个XML文件,OriginalXML和UpdatesXML,我需要将它们合并并保留最新的更改。我的用户基本上获得了OriginalXML的副本,进行编辑然后将更新提交给Web服务。我只需要使用UpdatesXML中较新的节点更新OriginalXML。
我可以遍历UpdatesXML中的节点,搜索OriginalXML以查找匹配项,检查时间戳并在更新更新时替换它:(类似于)
var OriginalXML = XDocument.Load("Original.xml");
var UpdatesXML = XDocument.Load("Updates.xml");
foreach (XElement WigitNode in UpdatesXML.Descendants("Wigit"))
{
//Find the corresponding OriginalXML node based on the Wigit/Subnode1/Id attribute
//Replace Original/Wigit with Updates/Wigit if Updates/Wigit/Editstamp/Timestamp attribute is later in Updates than Original
}
这一切对我来说似乎相当笨拙,特别是如果Updates.xml有很多节点的话。我的用例可能一次只有几十个,所以它可能不是问题,但似乎效率低下。是否有一个简单的XPath或xslt转换或更快或更高效的东西?
我的XML看起来像这样: Original.xml:
<?xml version="1.0" encoding="utf-8"?>
<Root>
<Wigit>
<EditStamp UserId="timmy" Timestamp="2013-09-13T20:22:00" />
<Subnode1 Id="A" />
</Wigit>
<Wigit>
<EditStamp UserId="phil" Timestamp="2013-09-13T21:51:00" />
<Subnode1 Id="B" />
</Wigit>
<Wigit>
<EditStamp UserId="biff" Timestamp="2013-10-13T21:51:00" />
<Subnode1 Id="C" />
</Wigit>
</Root>
Updates.xml:
<?xml version="1.0" encoding="utf-8"?>
<Root>
<Wigit>
<EditStamp UserId="frank" Timestamp="2013-10-13T22:00:00" />
<Subnode1 Id="A" />
</Wigit>
</Root>
所需的输出是:
<?xml version="1.0" encoding="utf-8"?>
<Root>
<Wigit>
<EditStamp UserId="frank" Timestamp="2013-10-13T22:00:00" />
<Subnode1 Id="A" />
</Wigit>
<Wigit>
<EditStamp UserId="phil" Timestamp="2013-09-13T21:51:00" />
<Subnode1 Id="B" />
</Wigit>
<Wigit>
<EditStamp UserId="biff" Timestamp="2013-10-13T21:51:00" />
<Subnode1 Id="C" />
</Wigit>
</Root>
更新时间:10-15-2013
我在下面使用Abhijeet Patel的代码做了一些调整,并想出了这个:
var query = from o in docOriginal.Element("Root").Elements("Wigit")
from u in docUpdate.Element("Root").Elements("Wigit")
let x = docUpdate.Element("Root")
.Elements("Wigit")
.SingleOrDefault(e => (e.Element("Subnode1").Attribute("id").Value == o.Element("Subnode1").Attribute("id").Value &&
DateTime.Parse(e.Element("EditStamp").Attribute("Timestamp").Value).Ticks > DateTime.Parse(o.Element("EditStamp").Attribute("Timestamp").Value).Ticks)) ?? o
select x;
XDocument merged = new XDocument(new XElement("Root", query));
return merged;
除了每个节点都重复之外,这给出了正确的结果:
<Root>
<Wigit>
<EditStamp UserId="frank" Timestamp="2013-10-13T22:00:00" />
<Subnode1 Id="SomeNewThing" />
</Wigit>
<Wigit>
<EditStamp UserId="frank" Timestamp="2013-10-13T22:00:00" />
<Subnode1 Id="SomeNewThing" />
</Wigit>
<Wigit>
<EditStamp UserId="phil" Timestamp="2013-09-13T21:51:00" />
<Subnode1 Id="B" />
</Wigit>
<Wigit>
<EditStamp UserId="phil" Timestamp="2013-09-13T21:51:00" />
<Subnode1 Id="B" />
</Wigit>
<Wigit>
<EditStamp UserId="biff" Timestamp="2013-10-13T21:51:00" />
<Subnode1 Id="C" />
</Wigit>
<Wigit>
<EditStamp UserId="biff" Timestamp="2013-10-13T21:51:00" />
<Subnode1 Id="C" />
</Wigit>
</Root>
有关如何不复制结果的任何提示?
2013年10月16日更新:
我获得重复结果的原因是因为我使用的更新文档有两个节点。代码需要一次处理多个更改,仅更新时间戳更大的节点。
string update = @"<?xml version='1.0' encoding='utf-8'?>
<Root>
<Wigit id='A'>
<EditStamp UserId='frank' Timestamp='2013-10-13T22:00:00' />
<Subnode1 Id='SomeNewThing' />
</Wigit>
<Wigit id='B'>
<EditStamp UserId='yomamma' Timestamp='2013-09-10T21:51:00' />
<Subnode1 Id='B' />
</Wigit>
</Root>";
答案 0 :(得分:2)
试试这个:
string original = @"<?xml version='1.0' encoding='utf-8'?>
<Root>
<Wigit>
<EditStamp UserId='timmy' Timestamp='2013-09-13T20:22:00' />
<Subnode1 Id='A' />
</Wigit>
<Wigit>
<EditStamp UserId='phil' Timestamp='2013-09-13T21:51:00' />
<Subnode1 Id='B' />
</Wigit>
<Wigit>
<EditStamp UserId='biff' Timestamp='2013-10-13T21:51:00' />
<Subnode1 Id='C' />
</Wigit>
</Root>";
string update = @"<?xml version='1.0' encoding='utf-8'?>
<Root>
<Wigit>
<EditStamp UserId='frank' Timestamp='2010-10-13T22:00:00' />
<Subnode1 Id='A' />
</Wigit>
<Wigit id='B'>
<EditStamp UserId='yomamma' Timestamp='2013-09-09T21:51:00' />
<Subnode1 Id='B' />
</Wigit>
</Root>";
XDocument docOriginal = XDocument.Parse(original);
XDocument docUpdate = XDocument.Parse(update);
var query = from o in docOriginal.Element("Root").Elements("Wigit")
let x = docUpdate.Element("Root")
.Elements("Wigit")
.SingleOrDefault(e =>
e.Element("Subnode1").Attribute("Id").Value == o.Element("Subnode1").Attribute("Id").Value
&& (DateTime.Parse(e.Element("EditStamp").Attribute("Timestamp").Value) > DateTime.Parse(o.Element("EditStamp").Attribute("Timestamp").Value))
) ?? o
select x;
XDocument merged = new XDocument(new XElement("Root", query));
Console.WriteLine(merged.ToString());