Chciałem sprawdzić, które z tych sugerowanych rozwiązań działa najlepiej, więc przeprowadziłem kilka testów porównawczych. W interesie porównałem również metody LINQ ze zwykłą starą metodą System.Xml sugerowaną przez Grega. Odmiana była interesująca i nie tego się spodziewałem, przy czym najwolniejsze metody były ponad 3 razy wolniejsze niż najszybsze .
Wyniki uporządkowane według najszybszego do najwolniejszego:
- CreateReader - łowca instancji (0,113 sekundy)
- Zwykły stary System.Xml - Greg Hurlman (0,134 sekundy)
- Agregowanie z konkatenacją ciągów - Mike Powell (0,324 sekundy)
- StringBuilder - Vin (0,333 sekundy)
- String.Join on array - Terry (0,360 sekundy)
- String.Concat na tablicy - Marcin Kosieradzki (0.364)
metoda
Użyłem pojedynczego dokumentu XML z 20 identycznymi węzłami (zwanymi „wskazówką”):
<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>
Liczby pokazane powyżej w sekundach są wynikiem wyodrębnienia „wewnętrznego kodu XML” 20 węzłów 1000 razy z rzędu i obliczenia średniej (średniej) z 5 przebiegów. Nie uwzględniłem czasu potrzebnego na załadowanie i przeanalizowanie XML do postaci XmlDocument
(dla metody System.Xml ) lub XDocument
(dla wszystkich pozostałych).
Użyte przeze mnie algorytmy LINQ to: (C # - wszystkie pobierają XElement
„rodzica” i zwracają wewnętrzny ciąg XML)
CreateReader:
var reader = parent.CreateReader();
reader.MoveToContent();
return reader.ReadInnerXml();
Agreguj z konkatenacją ciągów:
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 on array:
return String.Join("", parent.Nodes().Select(x => x.ToString()).ToArray());
String.Concat na tablicy:
return String.Concat(parent.Nodes().Select(x => x.ToString()).ToArray());
Nie pokazałem tutaj algorytmu "Zwykły stary System.Xml", ponieważ po prostu wywołuje .InnerXml na węzłach.
Wniosek
Jeśli ważna jest wydajność (np. Dużo XML, często parsowany), za CreateReader
każdym razem używałbym metody Daniela . Jeśli robisz tylko kilka zapytań, możesz użyć bardziej zwięzłej metody Aggregate Mike'a.
Jeśli używasz XML na dużych elementach z dużą liczbą węzłów (może 100), prawdopodobnie zaczniesz dostrzegać korzyści płynące z używania StringBuilder
metody Aggregate, ale nie ponad CreateReader
. Nie sądzę, aby metody Join
i Concat
były kiedykolwiek bardziej wydajne w tych warunkach ze względu na karę konwersji dużej listy na dużą tablicę (nawet oczywiste w przypadku mniejszych list).
parent.CreateNavigator().InnerXml
(potrzebausing System.Xml.XPath
metody rozszerzenia)..ToArray()
środka.Concat
, ale wydaje się, że przyspieszy to.ToString()
za tą odpowiedź . Wydaje się jeszcze szybsze ...var reader = parent.CreateReader();
w instrukcji using.Myślę, że jest to znacznie lepsza metoda (w VB nie powinna być trudna do przetłumaczenia):
Biorąc pod uwagę XElement x:
źródło
A co powiesz na użycie tej metody „rozszerzenia” na XElement? pracował dla mnie!
LUB użyj trochę Linq
Uwaga : powyższy kod musi być używany
element.Nodes()
w przeciwieństwie doelement.Elements()
. Bardzo ważna rzecz do zapamiętania różnicy między nimi.element.Nodes()
daje wszystko jakXText
,XAttribute
etc, aleXElement
tylko elementem.źródło
Z całym uznaniem dla tych, którzy odkryli i udowodnili najlepsze podejście (dzięki!), Tutaj jest to podsumowane metodą rozszerzającą:
źródło
Zachowaj prostotę i wydajność:
źródło
Skończyło się na tym:
źródło
Osobiście napisałem
InnerXml
metodę rozszerzającą przy użyciu metody Aggregate:Mój kod klienta jest wtedy tak samo zwięzły, jak w przypadku starej przestrzeni nazw System.Xml:
źródło
@Greg: Wygląda na to, że zredagowałeś swoją odpowiedź, tak aby była zupełnie inną odpowiedzią. Na co moja odpowiedź brzmi `` tak '', mogłem to zrobić za pomocą System.Xml, ale miałem nadzieję, że zmoczę stopy dzięki LINQ to XML.
Zostawię swoją oryginalną odpowiedź poniżej na wypadek, gdyby ktoś inny zastanawiał się, dlaczego nie mogę po prostu użyć właściwości .Value XElement, aby uzyskać to, czego potrzebuję:
@Greg: Właściwość Value łączy całą zawartość tekstową wszystkich węzłów podrzędnych. Więc jeśli element body zawiera tylko tekst, to działa, ale jeśli zawiera XHTML, otrzymuję cały tekst połączony razem, ale żaden z tagów.
źródło
<root>random text <sub1>child</sub1> <sub2>child</sub2></root>
), Która stała sięrandom text childchild
viaXElement.Parse(...).Value
// użycie Regex może być szybsze, aby po prostu przyciąć znacznik elementu początkowego i końcowego
źródło
IndexOf
:var xml = root.ToString(); var begin = xml.IndexOf('>')+1; var end = xml.LastIndexOf('<'); return xml.Substring(begin, end-begin);
doc.ToString () lub doc.ToString (SaveOptions) wykonuje całą pracę. Zobacz http://msdn.microsoft.com/en-us/library/system.xml.linq.xelement.tostring(v=vs.110).aspx
źródło
Czy można użyć obiektów przestrzeni nazw System.Xml, aby wykonać zadanie, zamiast używać LINQ? Jak już wspomniałeś, XmlNode.InnerXml jest dokładnie tym, czego potrzebujesz.
źródło
Zastanawiam się, czy (zauważ, że pozbyłem się b + = i po prostu mam b +)
może być nieco mniej wydajny niż
Nie jestem w 100% pewien ... ale patrząc na Aggregate () i string.Join () w Reflector ... Myślę , że czytam to jako Aggregate, po prostu dodając zwracaną wartość, więc zasadniczo otrzymujesz:
ciąg = ciąg + ciąg
w porównaniu z ciągiem znaków. Dołącz, jest tam wzmianka o FastStringAllocation lub czymś w tym rodzaju, co sprawia, że myślę, że ludzie z firmy Microsoft mogli dodać tam dodatkowy wzrost wydajności. Oczywiście moje .ToArray () nazywają moją negację w ten sposób, ale chciałem tylko zaoferować kolejną sugestię.
źródło
wiesz? najlepiej jest wrócić do CDATA :( szukam tutaj rozwiązań, ale myślę, że CDATA jest zdecydowanie najprostszym i najtańszym, a nie najwygodniejszym do rozwijania
źródło
Wykonam pracę za Ciebie
źródło
źródło