2008-10-28 45 views
5

Gần đây tôi đã sử dụng XPathDocument và XNavigator để phân tích một tệp XML cho một XPath và thuộc tính đã cho. Nó hoạt động rất tốt, khi tôi biết trước XPath là gì.Kiểm tra cách tốt nhất cho sự tồn tại XPath trong một tệp XML?

Đôi khi, XPath sẽ là một trong nhiều giá trị XPath có thể, và tôi muốn kiểm tra xem XPath đã tồn tại hay chưa.

Trong trường hợp tôi nhận được danh pháp sai, đây là những gì tôi đang kêu gọi một XPath - cho XML này blob:

<foo> 
    <bar baz="This is the value of the attribute named baz"> 
</foo> 

Tôi có thể tìm kiếm những gì tôi đang kêu gọi một XPath của "//foo/bar "và sau đó đọc thuộc tính" baz "để lấy giá trị.

Ví dụ về mã mà tôi sử dụng để làm điều này:

XPathDocument document = new XPathDocument(filename); 
XPathNavigator navigator = document.CreateNavigator(); 
XPathNavigator node = navigator.SelectSingleNode("//foo/bar"); 
if(node.HasAttributes) 
{ 
    Console.WriteLine(node.GetAttribute("baz", string.Empty)); 
} 

Bây giờ, nếu cuộc gọi đến navigator.SelectSingleNode thất bại, nó sẽ trả về một NullReferenceException hoặc một XPathException. Tôi có thể nắm bắt cả hai thứ đó và cấu trúc lại ở trên vào một thử nghiệm để xem liệu XPath có trả về một ngoại lệ hay không, nhưng tôi đã tự hỏi liệu có cách nào tốt hơn không?

Tôi không thấy bất kỳ điều gì rõ ràng trong Intellisense. XPathNavigator có .HasAttributes và .HasChildren nhưng ngắn lặp lại thông qua đường dẫn một nút tại một thời điểm, tôi không thấy bất cứ điều gì đẹp hơn để sử dụng.

+0

gì này có liên quan gì với LINQ? XPathNavigator và XPathDocument không phải là một phần của LINQ to XML. –

Trả lời

10

Nếu bạn đã cung cấp XPath hợp lệ nhưng không khớp với bất kỳ điều gì, SelectSingleNode sẽ không ném một NullReferenceException - nó sẽ chỉ trả về giá trị rỗng.

Nếu bạn vượt qua SelectSingleNode một số XPath cú pháp không hợp lệ, đó là khi nó sẽ ném một XPathException.

Vì vậy, thông thường, bạn chỉ cần kiểm tra xem giá trị trả lại có bằng không hay không.

+0

Đó là những gì tôi đang tìm kiếm, cảm ơn. –

0

Từ bộ nhớ, có thể chứa lỗi.

XDocument doc = XDocument.Load("foo.xml"); 

var att = from a in doc.Descendants("bar") 
      select a.Attribute("baz") 

foreach (var item in att) { 
    if (item != null) { ... } 
} 
+0

Vì tiêu đề câu hỏi đề cập đến LINQ, đây là cách tôi sẽ thực hiện. –

+0

Sử dụng.FirstOrDefault trên truy vấn nếu bạn muốn chỉ một –

0

Nếu node == null sau đó node.HasAttributes sẽ ném một NullReferenceException. Tình huống này sẽ xảy ra khi //foo/bar không khớp với bất kỳ phần tử nào trong tài liệu XML.

0
var node = XDocument.Load(filename) 
        .Descendants("bar") 
        .SingleOrDefault(e=>e.Attribute("baz") != null); 

if (node != null) Console.WriteLine(node.Attribute("baz").Value); 
1
var baz = navigator.SelectSingleNode("//foo/bar/@baz"); 
if (baz != null) Console.WriteLine(baz); 
0

Tôi có lẽ sẽ cụ thể hơn trong xpath của tôi.

 var doc = XDocument.Load(fileName); 

     var results = from r in doc.XPathSelectElements("/foo/bar[count(@baz) > 0]") 
         select r.Attribute("baz"); 

     foreach (String s in results) 
      Console.WriteLine(s); 
1

Tôi nghĩ việc tạo đối tượng XMLNode không tốt bằng cách thực hiện navigator.SelectSingleNode (...).

Bạn phải sử dụng navigator.Evaluate() thay vì:

if (Convert.ToBoolean(navigator.Evaluate(@"boolean(//foo/bar)"))) {...} 
+0

Tôi đã so sánh tốc độ của phương thức này so với SelectSingleNode, cho mỗi 500.000 lần lặp (với biểu thức XPath dưới dạng một chuỗi, chưa được biên dịch). Phương thức SelectSingleNode nhanh hơn 16-18% so với phương thức boolean. Tôi đã lặp lại bài kiểm tra nhiều lần và kết quả là nhất quán. –

Các vấn đề liên quan