Vra

Wat is die beste manier om die inhoud van die gemengde body element in die kode hieronder?Die element kan bevat óf XHTML of teks, maar ek wil net die inhoud daarvan in die string vorm.Die XmlElement tipe het die InnerXml eiendom wat is presies wat ek is na.

Die kode word soos dit geskryf is byna doen wat ek wil, maar sluit die omliggende <body>...</body> element, wat ek wil nie.

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()
                };
Was dit nuttig?

Oplossing

Ek wou sien watter een van hierdie voorgestelde oplossings die beste gevaar, so ek het 'n paar vergelykende toetse. Uit rente, ek vergelyk ook die LINQ metodes om die gewone ou System.Xml metode deur Greg voorgestel. Die variasie was interessant en nie wat ek verwag het, met die stadigste metodes om meer as 3 keer stadiger as die vinnigste .

Die resultate bestel deur vinnigste om stadigste:

  1. CreateReader - aanleg Hunter (0,113 sekondes)
  2. Plain ou System.Xml - Greg Hurlman (0,134 sekondes)
  3. Aggregate met 'n tou aaneenskakellling - Mike Powell (0,324 sekondes)
  4. StringBuilder - Vin (0,333 sekondes)
  5. String.Join op array - Terry (0,360 sekondes)
  6. String.Concat op array - Marcin Kosieradzki (0,364)

Metode

Ek gebruik 'n enkele XML dokument met 20 identiese nodes (genoem 'n wenk "):

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

Die getoon as sekondes getalle bo is die gevolg van onttrekking van die "innerlike XML" van die 20 knope, 1000 keer in 'n ry, en die neem van die gemiddelde (beteken) van 5 lopies. Ek het nie die tyd wat dit neem om te laai en te ontleed die XML in 'n XmlDocument (vir die System.Xml metode) of XDocument (vir al die ander).

Die LINQ algoritmes Ek gebruik was soos volg: (C # - al neem 'n XElement "ouer" en die standaard van die innerlike XML string)

CreateReader:

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

return reader.ReadInnerXml();

Aggregate met 'n tou aaneenskakellling:

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.Join op array:

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

String.Concat op array:

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

Ek het hier nie getoon die "gewone ou System.Xml" algoritme as dit net .InnerXml 'n beroep op nodes.


Gevolgtrekking

As prestasie is belangrik (bv baie XML, dikwels ontleed), Ek sal op gebruik Daniel se CreateReader metode elke keer . As jy net besig met 'n paar navrae, wil jy dalk om meer bondige Aggregate metode Mike se gebruik.

As jy 'n XML op groot elemente met baie van die nodusse (miskien 100's), sou jy waarskynlik begin om die voordele van die gebruik van StringBuilder oor die totale metode sien, maar nie meer as CreateReader. Ek dink nie die Join en Concat metodes sou ooit meer doeltreffend in hierdie toestande as gevolg van die straf van die omskakeling van 'n groot lys van 'n groot verskeidenheid (selfs voor die hand liggend hier met kleiner lyste) wees.

Ander wenke

Ek dink dit is 'n baie beter metode (in VB, moet nie moeilik wees om te vertaal):

Gegewe 'n XElement x:

Dim xReader = x.CreateReader
xReader.MoveToContent
xReader.ReadInnerXml

Hoe oor die gebruik van hierdie "uitbreiding" metode op XElement?vir my gewerk !

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

OF gebruik'n bietjie van die Linq

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

    return innerXml.ToString();
}

Nota:Die kode bo te gebruik element.Nodes() eerder as om te element.Elements().Baie belangrike ding om te onthou die verskil tussen die twee. element.Nodes() gee jou alles soos XText, XAttribute ens, maar XElement slegs'n Element.

(! Dankie)

Met alle krediet aan diegene wat ontdek en bewys die beste benadering, hier is dit is toegedraai in 'n uitbreiding metode:

public static string InnerXml(this XNode node) {
    using (var reader = node.CreateReader()) {
        reader.MoveToContent();
        return reader.ReadInnerXml();
    }
}

Hou dit eenvoudig en doeltreffend:

String.Concat(node.Nodes().Select(x => x.ToString()).ToArray())
  • Aggregate is geheue en prestasie ondoeltreffende wanneer concatenating snare
  • Met behulp Sluit ( "", sth) is die gebruik van twee keer groter string array as Concat ... En lyk baie vreemd in kode.
  • Die gebruik van + = lyk baie vreemd, maar blykbaar is nie veel erger as die gebruik van '+' -. Waarskynlik sal geoptimaliseer word om dieselfde kode, becase opdrag gevolg is ongebruikte en kan veilig verwyder word deur samesteller
  • StringBuilder is so noodsaaklik - en almal weet dat onnodige "staat" suig
  • .

Ek het uiteindelik met behulp van hierdie:

Body = t.Element("body").Nodes().Aggregate("", (b, node) => b += node.ToString());

Persoonlik, Ek het uiteindelik die skryf van 'n InnerXml uitbreiding metode gebruik te maak van die totale metode:

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

My kliënt kode is dan net so kortaf as dit sou wees met die ou System.Xml naamruimte:

var innerXml = myXElement.InnerXml();

@Greg: Dit wil voorkom jy jou antwoord het geredigeer om 'n heel ander antwoord wees. Waaraan my antwoord is ja, ek kon dit met behulp van System.Xml doen, maar het gehoop om my voete nat met LINQ kry om XML.

Ek sal my oorspronklike antwoord hieronder in geval iemand anders wonders laat die rede waarom ek nie net die XElement se .Value eiendom kan gebruik om te kry wat ek nodig het:

@Greg: Die Waarde eiendom Heg al die teks inhoud van enige kind nodes. So as die liggaam element bevat slegs teks dit werk, maar as dit XHTML bevat Ek kry al die teks saam saamgevoeg maar nie een van die etikette.

// behulp Regex dalk vinniger wees om bloot te knip die begin en einde element tag

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 () of doc.ToString (SaveOptions) doen die werk. Sien http: / /msdn.microsoft.com/en-us/library/system.xml.linq.xelement.tostring(v=vs.110).aspx

Is dit moontlik om die System.Xml naamruimte voorwerpe gebruik om die werk hier gedoen in plaas van die gebruik van LINQ kry? As jy reeds genoem, XmlNode.InnerXml is presies wat jy nodig het.

Wonder of (sien ek het ontslae te raak van die b + = en net b +)

t.Element( "body" ).Nodes()
 .Aggregate( "", ( b, node ) => b + node.ToString() );

effens minder doeltreffend kan wees as

string.Join( "", t.Element.Nodes()
                  .Select( n => n.ToString() ).ToArray() );

Nie 100% seker ... maar skrams by Aggregate () en string.Join () in Reflector ... I dink Ek lees dit as Aggregate net aanbring n terugkeer waarde, so in wese jou kry:

string = string + string

versus string.Join, dit het 'n paar noem in daar van FastStringAllocation of iets wat my ding die mense by Microsoft kan 'n paar ekstra prestasie hupstoot in daar sit maak. Natuurlik my .ToArray () noem my negate, maar ek wou net om te bied op 'n ander voorstel.

jy weet? die beste ding om te doen is om terug te CDATA :( im op soek na oplossings hier, maar ek dink CDATA is verreweg die eenvoudigste en goedkoopste, nie die mees geskikte om te ontwikkel met tho

var innerXmlAsText= XElement.Parse(xmlContent)
                    .Descendants()
                    .Where(n => n.Name.LocalName == "template")
                    .Elements()
                    .Single()
                    .ToString();

Sal doen die werk vir jou

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();
}
Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top