使用 Linq 和 XElement 检测 XML 中的结构差异
我正在尝试审核定制软件中使用的一些 XML。我能够使用“XNode.DeepEquals”检测相同结构的变化,然后向已更改的元素添加额外的属性,以便我可以突出显示它们。
我的问题是,当结构确实发生变化时,这种方法就会失败。 (我同时枚举两个 XElement,如果它们不相等,则执行 DeepEquals - 递归调用相同的方法来过滤出发生确切更改的位置)
显然,当我枚举并且节点为比较起来并不相同。请参阅下面的示例:
之前
<?xml version="1.0" encoding="utf-16"?>
<Prices xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Price default="true">
<Expression operator="Addition">
<LeftOperand>
<AttributeValue field="ccx_bandwidth" />
</LeftOperand>
<RightOperand>
<Constant value="10" type="Integer" />
</RightOperand>
</Expression>
</Price>
<Price default="false">
<Expression operator="Addition">
<LeftOperand>
<AttributeValue field="ccx_bandwidth" />
</LeftOperand>
<RightOperand>
<Constant value="99" type="Integer" />
</RightOperand>
</Expression>
</Price>
<RollupChildren />
之后
<?xml version="1.0" encoding="utf-16"?>
<Prices xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Price default="true">
<Expression operator="Addition">
<LeftOperand>
<AttributeValue field="ccx_bandwidth" />
</LeftOperand>
<RightOperand>
<Constant value="10" type="Integer" />
</RightOperand>
</Expression>
</Price>
<RollupChildren />
所以您可以看到后一个价格节点已被删除,我需要显示此更改。
目前,我可以访问这两个 xml 片段,并在审计应用程序加载时使用“auditchanged”属性修改它们,在我的 silverlight 应用程序中,我也使用转换器绑定了背景。
我一直在尝试 Linq to Xml 并考虑在查询中加入两个 XElement,但不确定如何继续。
理想情况下,我想做的是将两个 XElement 合并在一起,但添加一个单独的属性,具体取决于是否添加或删除它,然后我可以使用转换器绑定该属性,以适当地以红色或绿色突出显示。
有人对此有什么好主意吗? (我一直在研究 XmlDiff 但我不能在 Silverlight 中使用它,我不认为?)
I'm trying to audit some XML that is used in a bespoke piece of software. Im able to detect changes in identical structures using 'XNode.DeepEquals' and then adding an extra attribute to the elements that have changed so I can highlight them.
My problem is that, when the structure does change this methodology fails. ( I'm enumerating over both XElements at the same time performing a DeepEquals, if they are not equal - recursively calling the same method to filter out where the exact changes occurr )
Obviously this now falls apart when I'm enumerating and the nodes being compared are not the same. See Below Sample:
Before
<?xml version="1.0" encoding="utf-16"?>
<Prices xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Price default="true">
<Expression operator="Addition">
<LeftOperand>
<AttributeValue field="ccx_bandwidth" />
</LeftOperand>
<RightOperand>
<Constant value="10" type="Integer" />
</RightOperand>
</Expression>
</Price>
<Price default="false">
<Expression operator="Addition">
<LeftOperand>
<AttributeValue field="ccx_bandwidth" />
</LeftOperand>
<RightOperand>
<Constant value="99" type="Integer" />
</RightOperand>
</Expression>
</Price>
<RollupChildren />
After
<?xml version="1.0" encoding="utf-16"?>
<Prices xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Price default="true">
<Expression operator="Addition">
<LeftOperand>
<AttributeValue field="ccx_bandwidth" />
</LeftOperand>
<RightOperand>
<Constant value="10" type="Integer" />
</RightOperand>
</Expression>
</Price>
<RollupChildren />
So you can see that the latter Price Node has been removed and I need to show this change.
At the moment I have access to both pieces of xml and modify them on load of the audit application with an 'auditchanged' attribute which in my silverlight app i bind the background too with a converter.
I'd been playing around with Linq to Xml and looking at joining the two XElements in a query but wasn't sure how to proceed.
Ideally what I would like to do is merge the two XElements together but add a seperate attribute depending on if it's added or removed which i can then bind to with a converter to say highlight in red or green appropriately.
Does anyone have any bright ideas on this one? ( I'd been looking at XmlDiff however I can't use that in Silverlight, I don't think? )
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我在 codeblocks 库中有一个通用的不同类 http://codeblocks.codeplex.com
加载 XML 文档并处理每个文档作为 IEnumerable(扁平化 XML 树)应该允许您使用差异,如下所示:http://codeblocks.codeplex.com/wikipage?title=Differ%20Sample&referringTitle =Home
这是 diff.cs 的源代码:http://codeblocks.codeplex.com/SourceControl/changeset/view/96119#1887406
Diff原型是:
I have a generic differ class in the codeblocks library http://codeblocks.codeplex.com
Loading your XML documents and treating each document as an IEnumerable (flattened XML tree) should allow you to use the differ as shown here: http://codeblocks.codeplex.com/wikipage?title=Differ%20Sample&referringTitle=Home
Here's the source code for differ.cs: http://codeblocks.codeplex.com/SourceControl/changeset/view/96119#1887406
Diff prototype is:
这里重要的部分是后代查询。它将第一个文档中的每个元素放入其祖先列表中,其中每个项目都包含元素的名称及其在同名兄弟元素中的索引。我认为这可以以某种方式用于连接,尽管我不知道如何使用 linq 进行完全外部连接。因此,我只是使用这些列表来查找第二个文档中的元素,然后根据结果,可能将其标记为已删除或已更改。
The important part here is the descendants query. It turns every element in the first doc in a list of its ancestors, where every item contains the name of the element and it's index among its siblings of the same name. I think this can be somehow used for joining, though I have no idea how to do full outer join with linq. So instead i just use these lists to find elements in the second document, and then depending on the result, probably mark it as either deleted or changed.