Eu queria ver qual dessas soluções sugeridas apresentava melhor desempenho e, portanto, realizei alguns testes comparativos. Por interesse, também comparei os métodos LINQ com o método System.Xml antigo simples sugerido por Greg. A variação foi interessante e não o que eu esperava, com os métodos mais lentos sendo três vezes mais lentos que os mais rápidos .
Os resultados ordenados pelo mais rápido para o mais lento:
- CreateReader - Caçador de Instâncias (0,131 segundos)
- System.Xml antigo simples - Greg Hurlman (0.134 segundos)
- Agregado com concatenação de strings - Mike Powell (0.324 segundos)
- StringBuilder - Vin (0,333 segundos)
- String.Join na matriz - Terry (0,360 segundos)
- String.Concat na matriz - Marcin Kosieradzki (0.364)
Método
Eu usei um único documento XML com 20 nós idênticos (chamados 'dica'):
<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>
Os números mostrados como segundos acima são o resultado da extração do "XML interno" dos 20 nós, 1000 vezes seguidas e da média (média) de 5 execuções. Não incluí o tempo necessário para carregar e analisar o XML em um XmlDocument
(para o método System.Xml ) ou XDocument
(para todos os outros).
Os algoritmos LINQ que usei foram: (C # - todos pegam um XElement
"pai" e retornam a cadeia XML interna)
CreateReader:
var reader = parent.CreateReader();
reader.MoveToContent();
return reader.ReadInnerXml();
Agregue com concatenação de cadeias:
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 na matriz:
return String.Join("", parent.Nodes().Select(x => x.ToString()).ToArray());
String.Concat na matriz:
return String.Concat(parent.Nodes().Select(x => x.ToString()).ToArray());
Não mostrei o algoritmo "Plain System.Xml antigo" aqui, pois ele está chamando .InnerXml nos nós.
Conclusão
Se o desempenho for importante (por exemplo, muito XML, analisado com freqüência), eu usaria o CreateReader
método de Daniel toda vez . Se você está apenas fazendo algumas consultas, convém usar o método Aggregate, mais conciso, de Mike.
Se você estiver usando XML em elementos grandes com muitos nós (talvez 100), você provavelmente começará a ver o benefício de usar StringBuilder
o método Aggregate, mas não o acabou CreateReader
. Eu não acho que os métodos Join
e Concat
seriam mais eficientes nessas condições devido à penalidade de converter uma lista grande em uma grande variedade (até óbvio aqui com listas menores).
parent.CreateNavigator().InnerXml
(precisausing System.Xml.XPath
do método de extensão)..ToArray()
interior.Concat
, mas parece para torná-lo mais rápido.ToString()
acordo com esta resposta . Parece ainda mais rápido ...var reader = parent.CreateReader();
em uma instrução using.Eu acho que esse é um método muito melhor (no VB, não deve ser difícil de traduzir):
Dado um XElement x:
fonte
Que tal usar esse método de "extensão" no XElement? trabalhou para mim!
OU use um pouco de Linq
Nota : O código acima deve ser usado
element.Nodes()
em oposição aelement.Elements()
. Coisa muito importante para lembrar a diferença entre os dois.element.Nodes()
dá tudoXText
,XAttribute
etc, masXElement
apenas um elemento.fonte
Com todo o crédito devido a quem descobriu e provou a melhor abordagem (obrigado!), Aqui está envolvido em um método de extensão:
fonte
Mantenha-o simples e eficiente:
fonte
Acabei usando isso:
fonte
Pessoalmente, acabei escrevendo um
InnerXml
método de extensão usando o método Aggregate:Meu código de cliente é tão conciso quanto no antigo espaço para nome System.Xml:
fonte
@ Greg: Parece que você editou sua resposta para ser uma resposta completamente diferente. Em que minha resposta é sim, eu poderia fazer isso usando o System.Xml, mas esperava molhar os pés com o LINQ to XML.
Deixarei minha resposta original abaixo, caso alguém se pergunte por que não posso simplesmente usar a propriedade .Value do XElement para obter o que eu preciso:
@Greg: a propriedade Value concatena todo o conteúdo do texto de qualquer nó filho. Portanto, se o elemento body contiver apenas texto, ele funcionará, mas se ele contiver XHTML, reunirei todo o texto, mas nenhuma das tags.
fonte
<root>random text <sub1>child</sub1> <sub2>child</sub2></root>
) que se tornourandom text childchild
viaXElement.Parse(...).Value
// o uso do Regex pode ser mais rápido para simplesmente aparar a tag do elemento de início e fim
fonte
IndexOf
:var xml = root.ToString(); var begin = xml.IndexOf('>')+1; var end = xml.LastIndexOf('<'); return xml.Substring(begin, end-begin);
doc.ToString () ou doc.ToString (SaveOptions) faz o trabalho. Consulte http://msdn.microsoft.com/en-us/library/system.xml.linq.xelement.tostring(v=vs.110).aspx
fonte
É possível usar os objetos de espaço para nome System.Xml para concluir o trabalho aqui em vez de usar o LINQ? Como você já mencionou, XmlNode.InnerXml é exatamente o que você precisa.
fonte
Querendo saber se (note que eu me livrei do b + = e apenas tenho b +)
pode ser um pouco menos eficiente do que
Não 100% de certeza ... mas olhando para Aggregate () e String.Join () no refletor ... Eu acho que que li como Agregado apenas acrescentando um valor retornado, então, basicamente, você obtém:
string = string + string
Junte-se a isso, há alguma menção a FastStringAllocation ou algo assim, o que me faz pensar que o pessoal da Microsoft pode ter colocado um aumento extra no desempenho. É claro que meu .ToArray () chama isso de negar isso, mas eu só queria oferecer outra sugestão.
fonte
você sabe? a melhor coisa a fazer é voltar ao CDATA :( estou procurando soluções aqui, mas acho que o CDATA é de longe o mais simples e mais barato, não o mais conveniente para desenvolver com esse
fonte
Fará o trabalho para você
fonte
fonte