नाम पता जानने के बिना LINQ का उपयोग कर XDocument खोजें


81

नाम पता जानने के बिना एक XDocument खोजने का एक तरीका है? मेरे पास एक प्रक्रिया है जो सभी SOAP अनुरोधों को लॉग करती है और संवेदनशील डेटा को एन्क्रिप्ट करती है। मैं नाम के आधार पर कोई तत्व ढूंढना चाहता हूं। कुछ ऐसा है, मुझे सभी तत्व दें जहां नाम क्रेडिटकार्ड है। मुझे परवाह नहीं है कि नाम स्थान क्या है।

मेरी समस्या LINQ के साथ हो रही है और एक xml नामस्थान की आवश्यकता है।

मेरे पास अन्य प्रक्रियाएं हैं जो XML से मान प्राप्त करती हैं, लेकिन मैं इन अन्य प्रक्रियाओं के नाम स्थान को जानता हूं।

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");

मैं वास्तव में नामस्थान के बारे में जानने के बिना xml खोजने की क्षमता रखना चाहता हूं, कुछ इस तरह से:

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

यह काम नहीं करेगा क्योंकि मुझे संकलन समय पर नामस्थान पहले से नहीं पता है।

यह कैसे किया जा सकता है?

<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>      
        ...

एक अन्य प्रश्न से इस उत्तर को देखें: stackoverflow.com/questions/934486/…
मंकीवॉच

जवाबों:


90

जैसा कि एडम टिप्पणी में है, XName एक स्ट्रिंग के लिए परिवर्तनीय है, लेकिन जब एक होता है तो उस स्ट्रिंग को नाम स्थान की आवश्यकता होती है। यही कारण है कि .Name एक स्ट्रिंग के लिए विफल रहता है, या आप उनके नाम पर फ़िल्टर करने के लिए XLinq Method के पैरामीटर के रूप में "व्यक्ति" को पास क्यों नहीं कर सकते।
XName में एक उपसर्ग (Namespace) और एक LocalName होता है। स्थानीय नाम वही है जिसे आप क्वेरी करना चाहते हैं यदि आप नेमस्पेस को अनदेखा कर रहे हैं।
धन्यवाद एडम :)

आप .Dendendants () विधि के पैरामीटर के रूप में नोड का नाम नहीं रख सकते, लेकिन आप इस तरह से क्वेरी कर सकते हैं:

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>");

संपादित करें: मेरी परीक्षा से खराब कॉपी / अतीत :)

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

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

ये मेरे लिए सही है...


5
हो सकता है कि आपका उत्तर जिस तरह से है उसका कुछ स्पष्टीकरण देने में मदद करें: नाम एक XName है, और XName सिर्फ एक स्ट्रिंग के लिए परिवर्तनीय होने के लिए होता है, इसलिए एक स्ट्रिंग की .Name की तुलना प्रश्न पूछने वाले की क्वेरी के साथ विफल हो जाती है। XName में एक उपसर्ग और एक स्थानीय नाम होता है, और स्थानीय नाम वह होता है जिसे आप क्वेरी करना चाहते हैं यदि आप नेमस्पेस को अनदेखा कर रहे हैं।
एडम ने

टिप्पणी में था कि मैं somerockstar जवाब में डाल दिया है। मैं इसे स्पष्टता के लिए जोड़ सकता हूं, आप सही हैं
स्टीफन

त्वरित मदद के लिए बहुत बहुत धन्यवाद। उम्मीद है कि यह किसी और की मदद करेगा।
माइक बार्लो - बारदेव

आशा है कि, मैं उसी समस्या पर पहली बार XLinq का उपयोग कर अटक गया :)
स्टीफन

1
@ MikeBarlow-BarDev यह किया ;-)
Simon_Weaver

88

आप मूल-तत्व से नाम स्थान ले सकते हैं:

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

अब आप प्लस-ऑपरेटर का उपयोग करके आसानी से सभी वांछित तत्व प्राप्त कर सकते हैं:

root.Elements(ns + "CreditCardNumber")

यह बेहतर उत्तर की तरह लगता है, क्योंकि यह अभी भी आपको अधिकांश LINQसंचालन का उपयोग करने देता है ।
एहतेश चौधरी

6
यह उत्तर केवल तभी स्वीकार्य है जब कोई भी तत्व रूट नेम के रूप में अलग नामस्थान में न हो। हां, अगर आप केवल इसके लिए रूट डॉक्यूमेंट पूछते हैं, तो नामस्थान को जानना आसान है, लेकिन किसी भी नाम के किसी भी तत्व के लिए पूछने के लिए इसका ट्रिकियर, चाहे जो भी नामस्थान हो, वह तत्व हो सकता है। इसीलिए मैं जवाब का उपयोग XElement पर विचार करता हूं। Name.LocalName (आमतौर पर linq के माध्यम से) अधिक सामान्यीकृत हैं।
कालेब होल्ट

यह उत्तर पर्याप्त सामान्य नहीं है।
सेप्टको

14

मुझे लगता है कि मुझे वह मिला, जिसकी मुझे तलाश थी। आप निम्न कोड में देख सकते हैं मैं मूल्यांकन करता हूं Element.Name.LocalName == "CreditCardNumber"। यह मेरे परीक्षणों में काम करने लगा। मुझे यकीन नहीं है कि यह सबसे अच्छा अभ्यास है, लेकिन मैं इसका उपयोग करने जा रहा हूं।

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

अब मेरे पास ऐसे तत्व हैं जहां मैं मूल्यों को एन्क्रिप्ट कर सकता हूं।

यदि किसी के पास बेहतर समाधान है, तो कृपया इसे प्रदान करें। धन्यवाद।


यह एक सही समाधान है अगर आप नाम स्थान नहीं जानते हैं और न ही इसकी परवाह करते हैं। धन्यवाद!
SeriousM

2

यदि आपका XML दस्तावेज़ हमेशा उसी नोड Requestमें दिए गए नाम स्थान को परिभाषित करता है ( दिए गए दो उदाहरणों में नोड), तो आप इसे एक क्वेरी बनाकर और यह देख सकते हैं कि परिणाम का क्या नामस्थान है:

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;
}

2

हटाए गए विस्तार विधियों के साथ एक दो उत्तर हैं। यकीन नहीं है कि क्यों। यहां मेरा संस्करण है जो मेरी आवश्यकताओं के लिए काम करता है।

public static class XElementExtensions
{
    public static XElement ElementByLocalName(this XElement element, string localName)
    {
        return element.Descendants().FirstOrDefault(e => e.Name.LocalName == localName && !e.IsEmpty);
    }
}

IsEmptyसाथ नोड्स को फ़िल्टर करना हैx:nil="true"

अतिरिक्त सूक्ष्मताएं हो सकती हैं - इसलिए सावधानी के साथ उपयोग करें।


लवली! धन्यवाद साइमन। मैं लगभग यही कहूंगा कि यह एकमात्र सही उत्तर होना चाहिए .... यदि आप एक बार ऐसा कर रहे हैं तो आप इसे 100 बार कर रहे हैं और अन्य सभी उत्तर इसके मुकाबले बहुत ही भद्दे हैं: el.ElementByLocalName ("foo") ।
टिम कूपर

-7

बस वंश विधि का उपयोग करें:

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

3
वंशावली पैरामीटर XName के लिए पूछने के बाद से काम नहीं करेगा, और XName यहाँ एक नामस्थान द्वारा उपसर्ग है।
स्टीफन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.