XElement के InnerXml को पाने का सबसे अच्छा तरीका?

नीचे दिए गए कोड में मिश्रित body तत्व की सामग्री प्राप्त करने का सबसे अच्छा तरीका क्या है? तत्व में या तो एक्सएचटीएमएल या टेक्स्ट हो सकता है, लेकिन मैं सिर्फ स्ट्रिंग फॉर्म में अपनी सामग्री चाहता हूं। XmlElement प्रकार में InnerXml प्रॉपर्टी है जो ठीक है जो मैं कर रहा हूं।

The code as written almost does what I want, but includes the surrounding <body>...</body> element, which I don't want.

XDocument doc = XDocument.Load(new StreamReader(s));
var templates = from t in doc.Descendants("template")
                where t.Attribute("name").Value == templateName
                select new
                {
                   Subject = t.Element("subject").Value,
                   Body = t.Element("body").ToString()
                };
0
जोड़ा संपादित
विचारों: 4

13 उत्तर

LINQ का उपयोग करने के बजाय यहां काम करने के लिए System.Xml नेमस्पेस ऑब्जेक्ट्स का उपयोग करना संभव है? जैसा कि आपने पहले ही उल्लेख किया है, XmlNode.InnerXml बिल्कुल वही है जो आपको चाहिए।

0
जोड़ा

@ ग्रेग: ऐसा प्रतीत होता है कि आपने अपना जवाब पूरी तरह से अलग जवाब के रूप में संपादित कर लिया है। जिस पर मेरा जवाब हाँ है, मैं सिस्टम.एक्सएमएल का उपयोग करके ऐसा कर सकता था लेकिन मुझे अपने पैरों को LINQ से xml तक गीला करने की उम्मीद थी।

अगर मैं किसी और को आश्चर्यचकित करता हूं तो मैं नीचे अपना मूल उत्तर छोड़ दूंगा क्यों मैं XElement's का उपयोग नहीं कर सकता। वैल्यू प्रॉपर्टी जो मुझे चाहिए:

@ ग्रेग: वैल्यू प्रॉपर्टी किसी भी बच्चे नोड्स की सभी टेक्स्ट सामग्री को जोड़ती है। तो यदि शरीर तत्व में केवल पाठ होता है तो यह काम करता है, लेकिन यदि इसमें एक्सएचटीएमएल है तो मुझे सभी पाठ एक साथ संयोजित होते हैं लेकिन टैग में से कोई भी नहीं।

0
जोड़ा
मैं इस सटीक मुद्दे में भाग गया और सोचा कि यह एक बग था: मैंने 'मिश्रित' सामग्री (यानी यादृच्छिक पाठ बच्चा बच्चा ) जो XElement.Parse (...) के माध्यम से random text childchild बन गया। मान
जोड़ा लेखक drzaus, स्रोत

मैं इसका उपयोग कर समाप्त हुआ:

Body = t.Element("body").Nodes().Aggregate("", (b, node) => b += node.ToString());
0
जोड़ा
इस विधि ने मुझे वास्तव में आज बचाया, नए कन्स्ट्रक्टर के साथ XElement लिखने की कोशिश कर रहा था और अन्य तरीकों में से कोई भी इसे आसानी से उधार नहीं दे रहा था, जबकि यह एक किया था। धन्यवाद!
जोड़ा लेखक delliottg, स्रोत
यह बहुत सी स्ट्रिंग कॉन्सटेनेशन करेगा - मैं खुद को स्ट्रिंगबिल्डर के विन का उपयोग करना पसंद करूंगा। मैनुअल फोरच नकारात्मक नहीं है।
जोड़ा लेखक Marc Gravell, स्रोत

व्यक्तिगत रूप से, मैंने कुल विधि का उपयोग करके InnerXml एक्सटेंशन विधि लिखना समाप्त कर दिया:

public static string InnerXml(this XElement thiz)
{
   return thiz.Nodes().Aggregate( string.Empty, ( element, node ) => element += node.ToString() );
}

मेरा क्लाइंट कोड तब उतना ही छोटा है जितना पुराना सिस्टम होगा। एक्सएमएल नेमस्पेस:

var innerXml = myXElement.InnerXml();
0
जोड़ा

तुम्हे पता हैं? सबसे अच्छी बात यह है कि सीडीएटीए पर वापस जाना है :( मैं यहां समाधान देख रहा हूं लेकिन मुझे लगता है कि सीडीएटीए अब तक का सबसे सरल और सस्ता है, जो सबसे ज्यादा सुविधाजनक नहीं है

0
जोड़ा

उन लोगों को सभी देय क्रेडिट के साथ जिन्होंने सर्वोत्तम दृष्टिकोण (धन्यवाद!) खोजा और साबित किया, यहां एक विस्तार विधि में लपेटा गया है:

public static string InnerXml(this XNode node) {
    using (var reader = node.CreateReader()) {
        reader.MoveToContent();
        return reader.ReadInnerXml();
    }
}
0
जोड़ा

XElement पर इस "एक्सटेंशन" विधि का उपयोग करने के बारे में कैसे? मेरे लिए काम किया!

public static string InnerXml(this XElement element)
{
    StringBuilder innerXml = new StringBuilder();

    foreach (XNode node in element.Nodes())
    {
        // append node's xml string to innerXml
        innerXml.Append(node.ToString());
    }

    return innerXml.ToString();
}

या लिंक का एक छोटा सा उपयोग करें

public static string InnerXml(this XElement element)
{
    StringBuilder innerXml = new StringBuilder();
    doc.Nodes().ToList().ForEach( node => innerXml.Append(node.ToString()));

    return innerXml.ToString();
}

Note: The code above has to use element.Nodes() as opposed to element.Elements(). Very important thing to remember the difference between the two. element.Nodes() gives you everything like XText, XAttribute etc, but XElement only an Element.

0
जोड़ा

doc.ToString() or doc.ToString(SaveOptions) does the work. See http://msdn.microsoft.com/en-us/library/system.xml.linq.xelement.tostring(v=vs.110).aspx

0
जोड़ा

मुझे लगता है कि यह एक बेहतर तरीका है (वीबी में, अनुवाद करना मुश्किल नहीं होना चाहिए):

XElement x को देखते हुए:

Dim xReader = x.CreateReader
xReader.MoveToContent
xReader.ReadInnerXml
0
जोड़ा
एक्सएमएल रीडर डिस्पोजेबल है, इसलिए इसे इस्तेमाल करने के साथ लपेटना न भूलें, कृपया अगर मैं वीबी जानता हूं तो मैं खुद को जवाब संपादित करूंगा)।
जोड़ा लेखक Dmitry Fedorkov, स्रोत
+1 यह स्वीकार्य उत्तर होना चाहिए था। ल्यूक सैम्पसन का जवाब पढ़ने के लिए अच्छा है लेकिन आपने उसके सामने सही जवाब दिया है।
जोड़ा लेखक Bazzz, स्रोत
अच्छा! प्रस्तावित कुछ अन्य विधियों की तुलना में यह बहुत तेज है (मैंने उन सभी का परीक्षण किया - विवरण के लिए मेरा उत्तर देखें)। हालांकि उनमें से सभी नौकरी करते हैं, यह सबसे तेज़ करता है - यहां तक ​​कि System.Xml.Node.InnerXml से भी तेज है!
जोड़ा लेखक Luke Sampson, स्रोत
यह छोटा कोड स्निपेट बहुत उपयोगी था, यह स्वीकार्य उत्तर होना चाहिए था।
जोड़ा लेखक Frank Rosario, स्रोत

इसे सरल और कुशल रखें:

String.Concat(node.Nodes().Select(x => x.ToString()).ToArray())
  • तारों को संयोजित करते समय कुल मेमोरी और प्रदर्शन अक्षम होता है
  • जॉइन ("", sth) का उपयोग करना Concat की तुलना में दो गुना बड़ा स्ट्रिंग सरणी का उपयोग कर रहा है ... और कोड में काफी अजीब लग रहा है।
  • + का उपयोग करना बहुत अजीब लग रहा है, लेकिन स्पष्ट रूप से '+' का उपयोग करने से कहीं अधिक बुरा नहीं है - शायद उसी कोड पर अनुकूलित किया जाएगा, क्योंकि असाइनमेंट परिणाम अप्रयुक्त है और इसे संकलक द्वारा सुरक्षित रूप से हटाया जा सकता है।
  • स्ट्रिंगबिल्डर इतना जरूरी है - और सभी जानते हैं कि अनावश्यक "राज्य" बेकार है।
0
जोड़ा

मैं देखना चाहता था कि इनमें से कौन से सुझाए गए समाधान सर्वोत्तम प्रदर्शन करते हैं, इसलिए मैंने कुछ तुलनात्मक परीक्षण चलाए। ब्याज से, मैंने LINQ विधियों की तुलना ग्रेग द्वारा सुझाए गए सादे पुराने System.Xml विधि से भी की। भिन्नता दिलचस्प थी और मेरी अपेक्षा नहीं थी, सबसे धीमी विधियों सबसे तेज से 3 गुना धीमी होने के साथ।

परिणामों को सबसे तेज़ करने के लिए सबसे तेज़ आदेश दिया गया:

  1. CreateReader - इंस्टेंस हंटर (0.113 सेकेंड)
  2. सादा पुरानी प्रणाली। एक्सएमएल - ग्रेग हर्लमैन (0.134 सेकेंड)
  3. स्ट्रिंग कॉन्सटेनेशन के साथ कुल - माइक पॉवेल (0.324 सेकेंड)
  4. स्ट्रिंगबिल्डर - विन (0.333 सेकेंड)
  5. स्ट्रिंग। सरणी पर जुड़ें - टेरी (0.360 सेकेंड)
  6. स्ट्रिंग। सरणी पर कॉनकैट - मार्सीन कोसिएराडज़की (0.364)

विधि

मैंने 20 समान नोड्स (जिसे 'संकेत' कहा जाता है) के साथ एक एकल xml दस्तावेज़ का उपयोग किया:


  Thinking of using a fake address?
  
Please don't. If we can't verify your address we might just have to reject your application.

उपरोक्त सेकंड के रूप में दिखाए गए नंबर 20 नोड्स के "आंतरिक एक्सएमएल", पंक्ति में 1000 बार निकालने और 5 रनों के औसत (माध्य) को लेने का परिणाम हैं। मैंने एक्सएमएल को XmlDocument ( System.Xml विधि) के लिए लोड करने और XDocument के लिए एक्सएमएल को लोड करने के लिए लिया गया समय शामिल नहीं किया है ( अन्य सभी के लिए)।

The LINQ algorithms I used were: (C# - all take an XElement "parent" and return the inner xml string)

CreateReader:

var reader = parent.CreateReader();
reader.MoveToContent();

return reader.ReadInnerXml();

स्ट्रिंग concatenation के साथ कुल:

return parent.Nodes().Aggregate("", (b, node) => b += node.ToString());

StringBuilder:

StringBuilder sb = new StringBuilder();

foreach(var node in parent.Nodes()) {
    sb.Append(node.ToString());
}

return sb.ToString();

स्ट्रिंग। सरणी पर जुड़ें:

return String.Join("", parent.Nodes().Select(x => x.ToString()).ToArray());

स्ट्रिंग। सरणी पर कॉनकैट:

return String.Concat(parent.Nodes().Select(x => x.ToString()).ToArray());

मैंने यहां "सादा पुराना सिस्टम.एक्सएमएल" एल्गोरिदम नहीं दिखाया है क्योंकि यह सिर्फ कॉल कर रहा है। नोड्स परnerXml।


निष्कर्ष

यदि प्रदर्शन महत्वपूर्ण है (उदा। एक्सएमएल के बहुत सारे, अक्सर पार्स किए गए), तो मैं हर बार डैनियल के <�कोड> CreateReader विधि का उपयोग का उपयोग करूंगा। यदि आप केवल कुछ प्रश्न कर रहे हैं, तो आप माइक की संक्षिप्त संक्षिप्त विधि का उपयोग करना चाहेंगे।

यदि आप बहुत सारे नोड्स (शायद 100 के) वाले बड़े तत्वों पर एक्सएमएल का उपयोग कर रहे हैं, तो संभवतः आप कुल विधि पर StringBuilder का उपयोग करने का लाभ देखना शुरू कर देंगे, लेकिन CreateReader । मुझे नहीं लगता कि शामिल हों और Concat विधियां इन शर्तों में अधिक कुशल होंगी क्योंकि बड़ी सूची में एक बड़ी सूची में परिवर्तित करने के दंड के कारण (यहां तक ​​कि यहां भी स्पष्ट है छोटी सूचियां)।

0
जोड़ा
वाह, दिलचस्प सामान। इन्हें चलाने के लिए समय निकालने के लिए धन्यवाद!
जोड़ा लेखक Mike Powell, स्रोत
मैंने सोचा नहीं होगा कि आपको .ToArray() .Concat के अंदर चाहिए, लेकिन ऐसा लगता है कि यह तेज़ी से
जोड़ा लेखक drzaus, स्रोत
यदि आप इन उत्तरों के निचले भाग तक स्क्रॉल नहीं करते हैं: केवल .ooring() प्रति यह उत्तर । तेजी से लगता है ...
जोड़ा लेखक drzaus, स्रोत
स्ट्रिंगबिल्डर संस्करण को एक पंक्ति पर लिखा जा सकता है: var result = parent.Elements ()। कुल (नया स्ट्रिंगबिल्डर (), (एसबी, xelem) => sb.AppendLine (xelem.ToString ()), sb => sb.ToString ( ))
जोड़ा लेखक Softlion, स्रोत
सेकेंडिंग @ रिचर्ड की टिप्पणी। parent.CreateNavigator ()। InnerXml प्रक्षेपण के लिए विशेष रूप से अच्छा है क्योंकि यह इनलाइन है।
जोड़ा लेखक ccook, स्रोत
आपने एक्सटेंशन कोड के लिए parent.CreateNavigator ()। InnerXml (सिस्टम का उपयोग करके की आवश्यकता है) को याद किया है।
जोड़ा लेखक Richard, स्रोत
आपको वास्तव में उस कोड को var reader = parent.CreateReader (); को एक कथन कथन में लपेटना चाहिए।
जोड़ा लेखक BrainSlugs83, स्रोत
public static string InnerXml(this XElement xElement)
{
    //remove start tag
    string innerXml = xElement.ToString().Trim().Replace(string.Format("<{0}>", xElement.Name), "");
    ////remove end tag
    innerXml = innerXml.Trim().Replace(string.Format("</{0}>", xElement.Name), "");
    return innerXml.Trim();
}
0
जोड़ा
एक ही नाम के साथ नेस्टेड तत्वों के बारे में बात करें ...
जोड़ा लेखक Lucero, स्रोत

// Regex का उपयोग करना प्रारंभ और अंत तत्व टैग को ट्रिम करने के लिए तेज़ हो सकता है

var content = element.ToString();
var matchBegin = Regex.Match(content, @"<.+?>");
content = content.Substring(matchBegin.Index + matchBegin.Length);          
var matchEnd = Regex.Match(content, @"</.+?>", RegexOptions.RightToLeft);
content = content.Substring(0, matchEnd.Index);
0
जोड़ा
साफ। IndexOf : var xml = root.ToString() का उपयोग करने के लिए और भी तेज़; var start = xml.IndexOf ('>') + 1; var end = xml.LastIndexOf ('<'); xml.Substring वापस करें (प्रारंभ करें, अंत-प्रारंभ करें);
जोड़ा लेखक drzaus, स्रोत