c#
  • xml
  • linq-to-xml
  • 2013-04-15 4275 views 13 likes 
    13

    Tôi cố gắng truy vấn các phần tử từ một tệp hình ảnh * .csproj. Tôi đã tạo một ví dụ ngắn để minh họa sự cố:Truy vấn XDocument với thuộc tính xmlns (không gian tên)

    // Working 
        string xml1 = @"<Project ToolsVersion='4.0'> 
             <ItemGroup Label='Usings'> 
             <Reference Include='System' /> 
             <Reference Include='System.Xml' /> 
             </ItemGroup> 
            </Project>"; 
        // Not working 
        string xml2 = @"<Project ToolsVersion='4.0' xmlns='http://schemas.microsoft.com/developer/msbuild/2003'> 
             <ItemGroup Label='Usings'> 
             <Reference Include='System' /> 
             <Reference Include='System.Xml' /> 
             </ItemGroup> 
            </Project>"; 
    
        XDocument doc = XDocument.Parse(xml2); 
    
        foreach (XElement element in doc.Descendants("ItemGroup")) 
        { 
         Console.WriteLine(element); 
        } 
    

    Chuỗi xml1 hoạt động tốt, xml2 không trả lại bất kỳ thứ gì. Sự khác biệt duy nhất giữa các chuỗi là thuộc tính xmlns trong gốc tài liệu.

    Làm cách nào để truy vấn các tài liệu chứa thuộc tính xmlns? Tại sao lại là vấn đề khi tài liệu xml chứa thuộc tính xmlns?

    Trả lời

    16

    Tại sao sự cố khi tài liệu xml chứa thuộc tính xmlns?

    Nó không phải, nếu bạn hiểu ý nghĩa của nó :) Về cơ bản bạn đã áp dụng một mặc định namespace URI của "http://schemas.microsoft.com/developer/msbuild/2003" cho tất cả các yếu tố. Vì vậy, khi truy vấn, bạn cũng cần xác định không gian tên đó. May mắn thay, LINQ to XML làm cho điều đó thực sự đơn giản:

    XNamespace ns = "http://schemas.microsoft.com/developer/msbuild/2003"; 
    XDocument doc = XDocument.Parse(xml2); 
    foreach (XElement element in doc.Descendants(ns + "ItemGroup")) 
    { 
        Console.WriteLine(element); 
    } 
    
    +1

    Một cú pháp khác: 'doc.Descendants (" {http://schemas.microsoft.com/developer/msbuild/2003}ItemGroup ")' – ziya

    +1

    Xin lỗi tôi không hiểu tại sao chúng ta phải viết rõ ràng vùng tên nếu nó DEFAULT cho tài liệu này là gì? Lý do mà điều này không được giải quyết bởi XElement/XDocument chính nó tiềm ẩn là gì? –

    +0

    @FelixKeil: Bởi vì khi bạn gọi 'Element' hoặc' Descendants', bạn chỉ định 'XName', đủ điều kiện ... và tên đủ điều kiện bao gồm không gian tên. Tôi thấy quan điểm của bạn, nhưng tôi nghĩ rằng nó có ý nghĩa theo cách nó được thực hiện, và sự hỗ trợ không gian tên trong LINQ to XML là tốt nhất của bất kỳ API XML tôi đã nhìn thấy. –

    3

    Không cần phải biết trước vùng tên. Bạn có thể viết mã, hoạt động với cả Xml vì bạn có thể nhận được không gian tên mặc định từ XElement.

    XDocument doc = XDocument.Parse(xml2); 
    XNamespace ns = doc.Root.GetDefaultNamespace(); 
    foreach (XElement element in doc.Descendants(ns + "ItemGroup")) 
    { 
        Console.WriteLine(element); 
    } 
    

    Tôi cũng đã viết một phương pháp mở rộng để giải quyết XName từ bất kỳ XObject (XElement, XDocument, v.v ...).

    Lợi ích trong việc sử dụng phương pháp mở rộng thay vì GetDefaultNamespace là bạn không phải kiểm tra xem đã có một Không gian tên khác được cung cấp hay chưa.

    public static XName ResolveName(this XObject xObj, XName name) 
    { 
        //If no namespace has been added, use default namespace anyway 
        if (string.IsNullOrEmpty(name.NamespaceName)) 
        { 
         name = xObj.Document.Root.GetDefaultNamespace() + name.LocalName; 
        } 
        return name; 
    } 
    

    Bạn có thể sử dụng nó như thế này

    XDocument doc = XDocument.Parse(xml2); 
    foreach (XElement element in doc.Descendants(doc.ResolveName("ItemGroup"))) 
    { 
        Console.WriteLine(element); 
    } 
    

    Tôi nghĩ LINQ to XML là một API tuyệt vời. Nhưng tôi nghĩ rõ ràng, rằng nếu tôi không cung cấp một không gian tên, tôi luôn luôn có nghĩa là không gian tên mặc định. Tôi không thấy bất kỳ lý do tại sao LINQ to XML không hoạt động theo cách này. Đây là một nhược điểm nhỏ khiến tôi bực bội. Và lần đầu tiên với tư cách là người mới bắt đầu với LINQ to XML, tôi không biết mình đã làm gì sai trong nhiều giờ khi tôi quên cung cấp không gian tên mặc định.

    +0

    Tuyệt vời, cảm ơn bạn đã chia sẻ! – Joel

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