[英]What is the best way to compare XML files for equality?
我正在使用 .NET 2.0,最近的代碼更改使我之前的 Assert.AreEqual 調用(它比較了兩個 XML 字符串)無效。 在新的代碼庫中,實際上只有 XML 的一個元素是不同的,所以我希望所有其他元素的比較會給我想要的結果。 比較需要以編程方式完成,因為它是單元測試的一部分。
起初,我正在考慮使用幾個 XmlDocument 實例。 但后來我發現了這個: http : //drowningintechnicaldebt.com/blogs/scottroycraft/archive/2007/05/06/comparing-xml-files.aspx
看起來它可能有效,但我對 Stack Overflow 的反饋很感興趣,以防有更好的方法。
如果可能的話,我想避免為此添加另一個依賴項。
這實際上取決於您要檢查的“差異”。
現在,我們正在使用 Microsoft XmlDiff: http : //msdn.microsoft.com/en-us/library/aa302294.aspx
您可能會發現將 XML 解析為 XmlDocument 並將您的 Assert 調用建立在 XPath Query 上沒有那么脆弱。 以下是我經常使用的一些輔助斷言方法。 每個都有一個 XPathNavigator,您可以通過在 XmlDocument 或從文檔中檢索到的任何節點上調用 CreateNavigator() 來獲取它。 一個使用示例是:
XmlDocument doc = new XmlDocument( "Testdoc.xml" );
XPathNavigator nav = doc.CreateNavigator();
AssertNodeValue( nav, "/root/foo", "foo_val" );
AssertNodeCount( nav, "/root/bar", 6 )
private static void AssertNodeValue(XPathNavigator nav,
string xpath, string expected_val)
{
XPathNavigator node = nav.SelectSingleNode(xpath, nav);
Assert.IsNotNull(node, "Node '{0}' not found", xpath);
Assert.AreEqual( expected_val, node.Value );
}
private static void AssertNodeExists(XPathNavigator nav,
string xpath)
{
XPathNavigator node = nav.SelectSingleNode(xpath, nav);
Assert.IsNotNull(node, "Node '{0}' not found", xpath);
}
private static void AssertNodeDoesNotExist(XPathNavigator nav,
string xpath)
{
XPathNavigator node = nav.SelectSingleNode(xpath, nav);
Assert.IsNull(node, "Node '{0}' found when it should not exist", xpath);
}
private static void AssertNodeCount(XPathNavigator nav, string xpath, int count)
{
XPathNodeIterator nodes = nav.Select( xpath, nav );
Assert.That( nodes.Count, Is.EqualTo( count ) );
}
對xml
字符串進行簡單的字符串比較並不總是有效。 為什么 ?
例如兩者:
<MyElement></MyElmennt>
和<MyElment/>
從xml
角度來看是相等的..
有一些算法可以使xml
看起來總是一樣的,它們被稱為規范化算法。 .Net
支持規范化。
我寫了一個帶有序列化斷言的小型庫, source 。
樣本:
[Test]
public void Foo()
{
...
XmlAssert.Equal(expected, actual, XmlAssertOptions.IgnoreDeclaration | XmlAssertOptions.IgnoreNamespaces);
}
由於 XML 文件的內容可以具有不同的格式,並且在測試相等性時仍然被認為是相同的(從 DOM 的角度來看),因此您需要確定該相等性的度量是什么,例如是否忽略了格式? 元數據是否被忽略等定位很重要,很多邊緣情況。
通常,您會創建一個定義相等規則的類並將其用於比較,如果您的比較類實現了IEqualityComparer and/or IEqualityComparer<T>
接口,那么您的類可以在一堆內置框架列表中用作等式測試實現也是如此。 另外,當然,您可以根據需要根據需要以不同的方式衡量相等性。
IE
IEnumerable<T>.Contains
IEnumerable<T>.Equals
The constructior of a Dictionary etc etc
我最終得到了我想要的結果,代碼如下:
private static void ValidateResult(string validationXml, XPathNodeIterator iterator, params string[] excludedElements)
{
while (iterator.MoveNext())
{
if (!((IList<string>)excludedElements).Contains(iterator.Current.Name))
{
Assert.IsTrue(validationXml.Contains(iterator.Current.Value), "{0} is not the right value for {1}.", iterator.Current.Value, iterator.Current.Name);
}
}
}
在調用該方法之前,我以這種方式在 XmlDocument 的實例上創建了一個導航器:
XPathNavigator nav = xdoc.CreateNavigator();
接下來,我創建一個 XPathExpression 實例,如下所示:
XPathExpression expression = XPathExpression.Compile("/blah/*");
我在使用表達式創建迭代器后調用該方法:
XPathNodeIterator iterator = nav.Select(expression);
我仍在弄清楚如何進一步優化它,但它現在可以解決問題。
我做了一個方法來創建簡單的 XML 路徑。
static XElement MakeFromXPath(string xpath)
{
XElement root = null;
XElement parent = null;
var splits = xpath.Split('/'); //split xpath into parts
foreach (var split in splits)
{
var el = new XElement(split);
if (parent != null)
parent.Add(el);
else
root = el; //first element created, set as root
parent = el;
}
return root;
}
示例用法:
var element = MakeFromXPath("My/Path/To/Element")'
element
將包含值:
<My>
<Path>
<To>
<Element></Element>
</To>
</Path>
</My>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.