element, care nu't vrei.
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()
};
Am vrut să văd care dintre aceste soluții sugerate comportat cel mai bine, așa că am făcut niște teste comparative. De curiozitate, am comparat, de asemenea, LINQ metode de câmpie vechi System.Xml metoda propusă de Greg. Variația a fost interesant și nu ceea ce am așteptat, cu cel mai lent metode fiind mai mult de 3 ori mai lent decât cel mai rapid.
Rezultatele comandat prin cel mai rapid la cel mai lent:
****Metode de
Am folosit un singur document XML cu 20 de noduri identice (numit 'indicii'):
<hint>
<strong>Thinking of using a fake address?</strong>
<br />
Please don't. If we can't verify your address we might just
have to reject your application.
</hint>
Numerele afișate după câteva secunde de mai sus sunt rezultatul de extragere a "interior XML" de la 20 de noduri, de 1000 de ori într-un rând, și de a lua mediu (medie) de 5 puncte. Am't includ timpul necesar pentru a încărca și parse XML într-un XmlDocument
(pentru System.Xml metoda) sau XDocument
(pentru toate celelalte).
LINQ algoritmi-am folosit au fost: (C# - să ia toate o XElement
"părinte" și a reveni la interior XML string)
CreateReader:
var reader = parent.CreateReader();
reader.MoveToContent();
return reader.ReadInnerXml();
Agregat cu concatenarea string:
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();
String.Alăturați-vă pe matrice:
return String.Join("", parent.Nodes().Select(x => x.ToString()).ToArray());
String.Concat pe matrice:
return String.Concat(parent.Nodes().Select(x => x.ToString()).ToArray());
Nu am't demonstrat "Simplu vechiul Sistem.Xml" algoritmul de aici ca's a sunat .InnerXml pe noduri.
Concluzie
Dacă performanța este importantă (de exemplu, o mulțime de XML, analizat în mod frecvent), am'd utilizarea Daniel's CreateReader
metoda de fiecare dată. Daca're face doar câteva întrebări, s-ar putea doriți să utilizați Mike's mai concis Agregate metodă.
Daca're folosind XML pe elemente mari, cu o mulțime de noduri (poate 100's) ai'd începe, probabil, să vadă beneficiu de a folosi StringBuilder peste Agregate metoda, dar nu s-a terminat
CreateReader. Eu nu't cred că
se Alăture " și " Concat` metode ar fi mai eficientă în aceste condiții, pentru că de pedeapsa de a converti o listă mare pentru o gamă largă (chiar evident cu mici liste).
Cred că aceasta este o metoda mult mai buna (in VB, ar trebui't fi greu de tradus):
Având o XElement x:
Dim xReader = x.CreateReader
xReader.MoveToContent
xReader.ReadInnerXml
Cum despre utilizarea acestui "extensia" metoda pe XElement? a lucrat pentru mine !
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();
}
SAU de a folosi un pic de Linq
public static string InnerXml(this XElement element)
{
StringBuilder innerXml = new StringBuilder();
doc.Nodes().ToList().ForEach( node => innerXml.Append(node.ToString()));
return innerXml.ToString();
}
Notă: codul De mai sus pentru a utiliza element.Nodurile () "în opoziție cu" element.Elemente(). Lucru foarte important de reținut diferența între cele două.
element.Nodurile()dă totul ca
XText,
XAttributeetc, dar
XElement` doar un Element.
Cu toate datorate de credit pentru cei care au descoperit și s-a dovedit cea mai bună abordare (multumesc!), aici este înfășurat într-o metodă de prelungire:
public static string InnerXml(this XNode node) {
using (var reader = node.CreateReader()) {
reader.MoveToContent();
return reader.ReadInnerXml();
}
}
Păstrați-l simplu și eficient:
String.Concat(node.Nodes().Select(x => x.ToString()).ToArray())
Am încheiat cu asta:
Body = t.Element("body").Nodes().Aggregate("", (b, node) => b += node.ToString());
Personal, am ajuns să scriu o InnerXml
extinderea metoda se utilizează Agregate metoda:
public static string InnerXml(this XElement thiz)
{
return thiz.Nodes().Aggregate( string.Empty, ( element, node ) => element += node.ToString() );
}
Codul meu client este apoi doar concis ca ar fi cu cel vechi System.Xml nume:
var innerXml = myXElement.InnerXml();
@Greg: Se pare că'am editat raspunsul tau pentru a fi un răspuns complet diferit. La care raspunsul meu este da, am putea face acest lucru, folosind System.Xml dar a fost în speranța de a obține picioarele ude cu LINQ to XML.
Am'll las meu original de răspuns de mai jos în cazul în care altcineva se întreabă de ce nu pot't de a folosi doar XElement's .Valoarea de proprietate pentru a obține ceea ce am nevoie:
@Greg: Valoarea proprietății concateneaza toate conținutul de text de orice noduri copil. Deci, dacă organismul element conține doar text funcționează, dar dacă acesta conține XHTML am obține toate text concatenate împreună, dar nici unul dintre tag-uri.
// utilizarea Regex ar putea fi mai rapid să tăiați pur și simplu begin și end tag element
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);
doc.ToString() sau doc.ToString(SaveOptions) functioneaza. Vezi http://msdn.microsoft.com/en-us/library/system.xml.linq.xelement.tostring(v=vs. 110).aspx
var innerXmlAsText= XElement.Parse(xmlContent)
.Descendants()
.Where(n => n.Name.LocalName == "template")
.Elements()
.Single()
.ToString();
Va face treaba pentru tine
Vă întrebați dacă (observați că am scăpat de b+= și au doar b+)
t.Element( "body" ).Nodes()
.Aggregate( "", ( b, node ) => b + node.ToString() );
ar putea fi mai puțin eficiente decât
string.Join( "", t.Element.Nodes()
.Select( n => n.ToString() ).ToArray() );
Nu sunt 100% sigur...dar uitându-se la Agregate() și string.Join() în Reflector...I cred că a citit-o ca Agregat doar adăugarea unui revenind valoare, astfel încât, în esență, veți obține:
string = string + string
față de șir de caractere.Alăturați-vă, acesta are unele mai vorbim acolo de FastStringAllocation sau ceva, care mă face ceva cei de la Microsoft ar putea fi pus un extra boost de performanta acolo. Desigur mele .ToArray() apelul meu nega asta, dar am vrut doar sa ofer o altă sugestie.
Este posibil să se utilizeze System.Xml nume de obiecte pentru a obține locuri de muncă făcut aici în loc de a folosi LINQ? Ca te-a menționat deja, XmlNode.InnerXml este exact ceea ce ai nevoie.
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();
}