2010-04-09 23 views
62

Có cách nào để tìm kiếm một XDocument mà không biết không gian tên không? Tôi có một quá trình ghi lại tất cả các yêu cầu SOAP và mã hóa dữ liệu nhạy cảm. Tôi muốn tìm bất kỳ yếu tố nào dựa trên tên. Một cái gì đó như thế, cho tôi tất cả các yếu tố mà tên là CreditCard. Tôi không quan tâm không gian tên là gì.Tìm kiếm XDocument sử dụng LINQ mà không biết không gian tên

Sự cố của tôi dường như là với LINQ và yêu cầu không gian tên xml.

Tôi có các quy trình khác lấy giá trị từ XML, nhưng tôi biết không gian tên cho các quá trình khác này.

XDocument xDocument = XDocument.Load(@"C:\temp\Packet.xml"); 
XNamespace xNamespace = "http://CompanyName.AppName.Service.Contracts"; 

var elements = xDocument.Root 
         .DescendantsAndSelf() 
         .Elements() 
         .Where(d => d.Name == xNamespace + "CreditCardNumber"); 

Tôi thực sự muốn có khả năng tìm kiếm xml mà không biết về không gian tên, một cái gì đó như thế này:

XDocument xDocument = XDocument.Load(@"C:\temp\Packet.xml"); 
var elements = xDocument.Root 
         .DescendantsAndSelf() 
         .Elements() 
         .Where(d => d.Name == "CreditCardNumber") 

này sẽ không làm việc vì tôi không biết không gian tên trước tại thời gian biên dịch.

Làm cách nào để thực hiện điều này?

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> 
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Request xmlns="http://CompanyName.AppName.Service.ContractA"> 
     <Person> 
      <CreditCardNumber>83838</CreditCardNumber> 
      <FirstName>Tom</FirstName> 
      <LastName>Jackson</LastName> 
     </Person> 
     <Person> 
      <CreditCardNumber>789875</CreditCardNumber> 
      <FirstName>Chris</FirstName> 
      <LastName>Smith</LastName> 
     </Person> 
     ... 

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> 
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Request xmlns="http://CompanyName.AppName.Service.ContractsB"> 
     <Transaction> 
      <CreditCardNumber>83838</CreditCardNumber> 
      <TransactionID>64588</FirstName> 
     </Transaction>  
     ... 
+0

Xem câu trả lời này từ một câu hỏi khác: http://stackoverflow.com/questions/934486/how-do-i-get-a-nametable-from-an-xdocument/3977823#3977823 – MonkeyWrench

Trả lời

71

Như Adam precises trong các bình luận, XName là chuyển đổi thành một chuỗi, nhưng chuỗi đòi hỏi không gian tên khi có một. Đó là lý do tại sao việc so sánh tên .Name thành chuỗi không thành công hoặc tại sao bạn không thể chuyển "Người" làm tham số cho Phương thức XLinq để lọc tên của họ.
XName bao gồm tiền tố (Không gian tên) và LocalName. Tên cục bộ là những gì bạn muốn truy vấn nếu bạn bỏ qua các không gian tên.
Cảm ơn bạn Adam :)

Bạn không thể đặt tên của nút như một tham số của .Descendants() phương pháp, nhưng bạn có thể truy vấn theo cách đó:

var doc= XElement.Parse(
@"<s:Envelope xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/""> 
<s:Body xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> 
    <Request xmlns=""http://CompanyName.AppName.Service.ContractA""> 
    <Person> 
     <CreditCardNumber>83838</CreditCardNumber> 
     <FirstName>Tom</FirstName> 
     <LastName>Jackson</LastName> 
    </Person> 
    <Person> 
     <CreditCardNumber>789875</CreditCardNumber> 
     <FirstName>Chris</FirstName> 
     <LastName>Smith</LastName> 
    </Person> 
    </Request> 
    </s:Body> 
</s:Envelope>"); 

EDIT:xấu copy/quá khứ từ thử nghiệm của tôi :)

var persons = from p in doc.Descendants() 
       where p.Name.LocalName == "Person" 
       select p; 

foreach (var p in persons) 
{ 
    Console.WriteLine(p); 
} 

đó làm việc cho tôi ...

+3

Có thể giúp đưa ra một số giải thích về * tại sao * câu trả lời của bạn là cách nó là: Tên là một XName, và XName chỉ xảy ra có thể chuyển đổi thành chuỗi, do đó so sánh .Name thành chuỗi không thành công với truy vấn của người hỏi . XName bao gồm một tiền tố và một tên địa phương, và tên địa phương là những gì bạn muốn truy vấn nếu bạn đang bỏ qua các không gian tên. –

+0

đó là trong nhận xét mà tôi đã đưa vào câu trả lời somerockstar. Tôi có thể thêm điều này cho rõ ràng, bạn đang phải –

+0

Cảm ơn rất nhiều vì sự giúp đỡ nhanh chóng. Hy vọng rằng điều này sẽ giúp người khác. –

-6

Chỉ cần sử dụng các phương pháp con cháu:

XDocument doc = XDocument.Load(filename); 
String[] creditCards = (from creditCardNode in doc.Root.Descendents("CreditCardNumber") 
         select creditCardNode.Value).ToArray<string>(); 
+2

không hoạt động kể từ khi tham số con cháu yêu cầu một XName, và XName là tiền tố của một không gian tên ở đây. –

8

Tôi nghĩ rằng tôi đã tìm thấy những gì tôi đang tìm kiếm. Bạn có thể thấy trong đoạn mã sau tôi thực hiện đánh giá Element.Name.LocalName == "CreditCardNumber". Điều này dường như làm việc trong các thử nghiệm của tôi. Tôi không chắc đó có phải là cách hay nhất hay không, nhưng tôi sẽ sử dụng nó.

XDocument xDocument = XDocument.Load(@"C:\temp\Packet.xml"); 
var elements = xDocument.Root.DescendantsAndSelf().Elements().Where(d => d.Name.LocalName == "CreditCardNumber"); 

Bây giờ tôi có các yếu tố mà tôi có thể mã hóa các giá trị.

Nếu có ai có giải pháp tốt hơn, vui lòng cung cấp giải pháp đó. Cảm ơn.

2

Nếu tài liệu XML của bạn luôn luôn xác định không gian tên trong cùng một nút (Request nút trong hai ví dụ đưa ra), bạn có thể xác định nó bằng cách thực hiện một truy vấn và nhìn thấy những gì không gian tên kết quả có:

XDocument xDoc = XDocument.Load("filename.xml"); 
//Initial query to get namespace: 
var reqNodes = from el in xDoc.Root.Descendants() 
       where el.Name.LocalName == "Request" 
       select el; 
foreach(var reqNode in reqNodes) 
{ 
    XNamespace xns = reqNode.Name.Namespace; 
    //Queries making use of namespace: 
    var person = from el in reqNode.Elements(xns + "Person") 
       select el; 
} 
76

Bạn có thể mất không gian tên từ gốc phần tử:

XDocument xDocument = XDocument.Load(@"C:\temp\Packet.xml"); 
var ns = xDocument.Root.Name.Namespace; 

Bây giờ bạn có thể nhận được tất cả các yếu tố mong muốn một cách dễ dàng bằng cách sử dụng cộng điều hành:

root.Elements(ns + "CreditCardNumber") 
+0

Điều này có vẻ như là câu trả lời tốt hơn, vì nó vẫn cho phép bạn sử dụng phần lớn các hoạt động 'LINQ'. –

+1

Câu trả lời này chỉ chấp nhận được nếu không có phần tử nào trong không gian tên khác với tài liệu gốc. Vâng, thật dễ dàng để biết không gian tên nếu bạn chỉ yêu cầu tài liệu gốc cho nó, nhưng nó phức tạp hơn để yêu cầu bất kỳ phần tử nào của một tên cụ thể, bất kể không gian tên nào chính yếu tố đó có thể ở. Đó là lý do tại sao tôi xem xét việc sử dụng câu trả lời XElement.Name.LocalName (thường thông qua LINQ) được tổng quát hơn. –

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