किसी भी गहराई पर नाम से तत्वों के लिए एक XDocument क्वेरी


143

मेरे पास एक XDocumentवस्तु है। मैं LINQ का उपयोग करके किसी विशेष नाम के तत्वों के लिए क्वेरी करना चाहता हूं। जब मैं उपयोग करता हूं Descendants("element_name"), मुझे केवल ऐसे तत्व मिलते हैं जो वर्तमान स्तर के प्रत्यक्ष बच्चे हैं। मैं जो देख रहा हूं वह XPath में "// element_name" के बराबर है ... क्या मुझे बस उपयोग करना चाहिए XPath, या LINQ विधियों का उपयोग करने का कोई तरीका है? धन्यवाद।

जवाबों:


213

वंशज बिल्कुल ठीक काम करना चाहिए। यहाँ एक उदाहरण है:

using System;
using System.Xml.Linq;

class Test
{
    static void Main()
    {
        string xml = @"
<root>
  <child id='1'/>
  <child id='2'>
    <grandchild id='3' />
    <grandchild id='4' />
  </child>
</root>";
        XDocument doc = XDocument.Parse(xml);

        foreach (XElement element in doc.Descendants("grandchild"))
        {
            Console.WriteLine(element);
        }
    }
}

परिणाम:

<grandchild id="3" />
<grandchild id="4" />


1
यदि किसी तत्व का नाम एक xml दस्तावेज़ में डुप्लिकेट किया गया था, तो आप इससे कैसे निपटेंगे? उदाहरण के लिए: यदि xml में <Part> के उप तत्वों के साथ <Cars> का संग्रह होता है, और <Plan> के उप तत्वों के साथ <Planes> का संग्रह भी होता है, और आप केवल Cars के लिए भागों की एक सूची चाहते हैं।
फफूंद

12
@ पफ्स: तब मैं उपयोग करूँगा doc.Descendants("Cars").Descendants("Part")(या संभवतः .Elements("Part")यदि वे केवल सीधे बच्चे थे।
जॉन स्कीट

8
छह साल और अभी भी एक शानदार उदाहरण है। वास्तव में, यह अभी भी MSDN स्पष्टीकरण की तुलना में कहीं अधिक उपयोगी है :-)
EvilDr

और यह अभी भी एक दुष्ट उदाहरण है, डॉ, क्योंकि अगर "कार" नहीं हैं, तो उपरोक्त कोड एक एनपीई में परिणाम देगा। हो सकता है ।? नए C # से अंत में इसे वैध बनाया जाएगा
Dror Harari

3
@DrorHarari नहीं, कोई अपवाद नहीं फेंका गया है: आज़माएं var foo = new XDocument().Descendants("Bar").Descendants("Baz"); क्योंकि Descendantsखाली IEnumerable<XElement>और वापस नहीं null
डेरेड्यूड

54

नामस्थान का संकेत करने वाला एक उदाहरण:

String TheDocumentContent =
@"
<TheNamespace:root xmlns:TheNamespace = 'http://www.w3.org/2001/XMLSchema' >
   <TheNamespace:GrandParent>
      <TheNamespace:Parent>
         <TheNamespace:Child theName = 'Fred'  />
         <TheNamespace:Child theName = 'Gabi'  />
         <TheNamespace:Child theName = 'George'/>
         <TheNamespace:Child theName = 'Grace' />
         <TheNamespace:Child theName = 'Sam'   />
      </TheNamespace:Parent>
   </TheNamespace:GrandParent>
</TheNamespace:root>
";

XDocument TheDocument = XDocument.Parse( TheDocumentContent );

//Example 1:
var TheElements1 =
from
    AnyElement
in
    TheDocument.Descendants( "{http://www.w3.org/2001/XMLSchema}Child" )
select
    AnyElement;

ResultsTxt.AppendText( TheElements1.Count().ToString() );

//Example 2:
var TheElements2 =
from
    AnyElement
in
    TheDocument.Descendants( "{http://www.w3.org/2001/XMLSchema}Child" )
where
    AnyElement.Attribute( "theName" ).Value.StartsWith( "G" )
select
    AnyElement;

foreach ( XElement CurrentElement in TheElements2 )
{
    ResultsTxt.AppendText( "\r\n" + CurrentElement.Attribute( "theName" ).Value );
}

2
लेकिन, क्या होगा अगर मेरे स्रोत xml में नाम स्थान नहीं है? मुझे लगता है कि मैं एक को कोड में जोड़ सकता हूं (उस पर गौर करना होगा), लेकिन ऐसा क्यों जरूरी है? किसी भी घटना में, root.Descendants ("myTagName") को मेरे कोड में तीन या चार स्तर गहरे दबे हुए तत्व नहीं मिलते हैं।
EoRaptor013

2
धन्यवाद! हम डाटाकंट्रेक्ट क्रमांकन का उपयोग कर रहे हैं। यह <MyClassEntries xmlns: i = " w3.org/2001/XMLSchema-instance " xmlns = " schemas.datacontract.org/2004/07/DataLayer.yClass "> जैसा हैडर बनाता है और मुझे ऐसा क्यों महसूस नहीं हो रहा था। कोई वंशज। मुझे { schemas.datacontract.org/2004/07/DataLayer.MyClass } उपसर्ग जोड़ने की आवश्यकता थी ।
किम

38

आप इसे इस तरह से कर सकते हैं:

xml.Descendants().Where(p => p.Name.LocalName == "Name of the node to find")

जहां xmlएक है XDocument

ध्यान रखें कि संपत्ति Nameएक वस्तु है कि एक LocalNameऔर एक है देता है Namespace। इसीलिए Name.LocalNameअगर आपको नाम से तुलना करनी हो तो आपको इस्तेमाल करना होगा।


मैं c # प्रोजेक्ट फ़ाइल से सभी एंबेडेडResource नोड प्राप्त करने की कोशिश कर रहा हूं, और यह केवल एक ही तरीका है जो काम करता है। XDocument दस्तावेज़ = XDocument.Load (csprojPath); IEnumerable <XElement> एम्बेडेडResourceElements = document.Descendants ("एंबेडेडResource"); काम नहीं कर रहा है और मुझे समझ नहीं आता कि क्यों।
यूजीन

22

वंशज वही करेंगे जो आपको चाहिए, लेकिन यह सुनिश्चित करें कि आपने तत्व के नाम के साथ नाम स्थान का नाम शामिल किया है। यदि आप इसे छोड़ देते हैं, तो आपको संभवतः एक खाली सूची मिल जाएगी।


11

इसे पूरा करने के दो तरीके हैं,

  1. LINQ करने वाली एक्सएमएल
  2. XPath

इन दृष्टिकोणों का उपयोग करने के नमूने निम्नलिखित हैं,

List<XElement> result = doc.Root.Element("emails").Elements("emailAddress").ToList();

यदि आप XPath का उपयोग करते हैं, तो आपको IEnumerable के साथ कुछ हेरफेर करने की आवश्यकता है:

IEnumerable<XElement> mails = ((IEnumerable)doc.XPathEvaluate("/emails/emailAddress")).Cast<XElement>();

ध्यान दें कि

var res = doc.XPathEvaluate("/emails/emailAddress");

परिणाम या तो एक शून्य सूचक है, या कोई परिणाम नहीं है।


1
सिर्फ XPathEvaluateउस System.Xml.XPathनामस्थान में है।
ताहिर हसन

XPathEvaluate को ट्रिक करनी चाहिए, लेकिन आपकी क्वेरी केवल एक विशेष गहराई (एक) पर नोड्स लेती है। यदि आप "ईमेल" नाम के सभी तत्वों का चयन करना चाहते हैं, चाहे वे किसी दस्तावेज़ में हों, तो आप "// ईमेल" पथ का उपयोग करेंगे। जाहिर है कि इस तरह के रास्ते अधिक महंगे हैं, क्योंकि पूरे पेड़ को चलना चाहिए जो भी नाम है, लेकिन यह काफी सुविधाजनक हो सकता है - बशर्ते आप जानते हैं कि आप क्या कर रहे हैं।
द डग

8

मैं XPathSelectElementsविस्तार विधि का उपयोग कर रहा हूं जो विधि के समान तरीके से काम करती है XmlDocument.SelectNodes:

using System;
using System.Xml.Linq;
using System.Xml.XPath; // for XPathSelectElements

namespace testconsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            XDocument xdoc = XDocument.Parse(
                @"<root>
                    <child>
                        <name>john</name>
                    </child>
                    <child>
                        <name>fred</name>
                    </child>
                    <child>
                        <name>mark</name>
                    </child>
                 </root>");

            foreach (var childElem in xdoc.XPathSelectElements("//child"))
            {
                string childName = childElem.Element("name").Value;
                Console.WriteLine(childName);
            }
        }
    }
}

1

@Francisco गोल्डनस्टीन के उत्तर के बाद, मैंने एक विस्तार विधि लिखी

using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace Mediatel.Framework
{
    public static class XDocumentHelper
    {
        public static IEnumerable<XElement> DescendantElements(this XDocument xDocument, string nodeName)
        {
            return xDocument.Descendants().Where(p => p.Name.LocalName == nodeName);
        }
    }
}

0

हम जानते हैं कि उपरोक्त सत्य है। जॉन कभी गलत नहीं होता; वास्तविक जीवन की इच्छाएं थोड़ी और बढ़ सकती हैं

<ota:OTA_AirAvailRQ
    xmlns:ota="http://www.opentravel.org/OTA/2003/05" EchoToken="740" Target=" Test" TimeStamp="2012-07-19T14:42:55.198Z" Version="1.1">
    <ota:OriginDestinationInformation>
        <ota:DepartureDateTime>2012-07-20T00:00:00Z</ota:DepartureDateTime>
    </ota:OriginDestinationInformation>
</ota:OTA_AirAvailRQ>

उदाहरण के लिए, आमतौर पर समस्या यह है कि हम ऊपर दिए गए xml दस्तावेज़ में EchoToken कैसे प्राप्त कर सकते हैं? या एट्रिब्यूट नाम के साथ तत्व को कैसे धुंधला करना है।

1- आप नीचे दिए गए नाम और नाम के साथ पहुंचकर उन्हें पा सकते हैं

doc.Descendants().Where(p => p.Name.LocalName == "OTA_AirAvailRQ").Attributes("EchoToken").FirstOrDefault().Value

2- आप इसे इस तरह की विशेषता सामग्री मूल्य द्वारा पा सकते हैं


0

वर्ग के आधार पर Linqऔर वंश विधि के आधार पर समाधान का यह मेरा संस्करण हैXDocument

using System;
using System.Linq;
using System.Xml.Linq;

class Test
{
    static void Main()
    {
        XDocument xml = XDocument.Parse(@"
        <root>
          <child id='1'/>
          <child id='2'>
            <subChild id='3'>
                <extChild id='5' />
                <extChild id='6' />
            </subChild>
            <subChild id='4'>
                <extChild id='7' />
            </subChild>
          </child>
        </root>");

        xml.Descendants().Where(p => p.Name.LocalName == "extChild")
                         .ToList()
                         .ForEach(e => Console.WriteLine(e));

        Console.ReadLine();
    }
}

परिणाम:

Desendantsविधि के बारे में अधिक जानकारी के लिए यहां एक नज़र डालें।


-1

(कोड और निर्देश C # के लिए है और अन्य भाषाओं के लिए थोड़ा बदलना पड़ सकता है)

यह उदाहरण एकदम सही काम करता है यदि आप एक पेरेंट नोड से पढ़ना चाहते हैं जिसमें कई बच्चे हैं, उदाहरण के लिए निम्न XML को देखें;

<?xml version="1.0" encoding="UTF-8"?> 
<emails>
    <emailAddress>jdoe@set.ca</emailAddress>
    <emailAddress>jsmith@hit.ca</emailAddress>
    <emailAddress>rgreen@set_ig.ca</emailAddress> 
</emails>

अब नीचे दिए गए इस कोड के साथ (यह ध्यान में रखते हुए कि XML फ़ाइल संसाधनों में संग्रहीत है (संसाधनों पर मदद के लिए स्निपेट के अंत में लिंक देखें) आप "ईमेल" टैग के भीतर प्रत्येक ईमेल पते को प्राप्त कर सकते हैं।

XDocument doc = XDocument.Parse(Properties.Resources.EmailAddresses);

var emailAddresses = (from emails in doc.Descendants("emailAddress")
                      select emails.Value);

foreach (var email in emailAddresses)
{
    //Comment out if using WPF or Windows Form project
    Console.WriteLine(email.ToString());

   //Remove comment if using WPF or Windows Form project
   //MessageBox.Show(email.ToString());
}

परिणाम

  1. jdoe@set.ca
  2. jsmith@hit.ca
  3. rgreen@set_ig.ca

नोट: कंसोल एप्लिकेशन और WPF या विंडोज फॉर्म के लिए आपको "System.Xml.Linq का उपयोग करके" जोड़ना होगा; अपने प्रोजेक्ट के शीर्ष पर निर्देश का उपयोग करना, कंसोल के लिए आपको यूज़िंग निर्देश को जोड़ने से पहले इस नाम स्थान का संदर्भ भी जोड़ना होगा। कंसोल के लिए भी "गुण फ़ोल्डर" के तहत डिफ़ॉल्ट रूप से कोई संसाधन फ़ाइल नहीं होगी, इसलिए आपको मैन्युअल रूप से संसाधन फ़ाइल को जोड़ना होगा। नीचे MSDN लेख, इस बारे में विस्तार से बताएं।

संसाधन जोड़ना और संपादन करना

कैसे करें: संसाधन जोड़ें या निकालें


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