最好的方式得到InnerXml的一个T?
题
什么是最好的方式获得的内容混合 body
元素在代码下面?元素可能包含XHTML或文本,但我只是希望其中的内容串的形式。的 XmlElement
类型的 InnerXml
酒店,这正是我之后。
为编写的代码 几乎 的确我想要什么,但是包括周围 <body>
...</body>
元件,我不想要。
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()
};
解决方案
我想看到这些建议的解决方案进行最好,所以我跑了一些比较试验。出来的兴趣,我也相比皇宫方法的普通老 System.Xml 方法的建议通过格雷格。变化是有趣的,并不是我预期,与最慢的方法 3倍的速度慢于最快的.
结果,下令由最快到最慢:
- CreateReader实例猎人(0.113的秒)
- 普通老System.Xml -格雷格Hurlman(0.134秒)
- 总有字符串连接-迈克*鲍威尔(0.324秒)
- StringBuilder-Vin(0.333秒)
- String.加入上列-特里(0.360秒)
- String.Concat上阵列-马尔Kosieradzki(0.364)
方法
我用一个单一的XML文件的有相同的20节点(被称为'hint'):
<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>
所示的数字为秒以上结果中提取的"内XML"的20个节点,1000次,并把平均的(平均值)的5运行。我不包括所花费的时间负载和分析XML成 XmlDocument
(对的 System.Xml 法)或 XDocument
(对所有其他人)。
皇宫的算法我使用的是: (C#-所采取的一个 XElement
"父母"和返回的内部XML string)
CreateReader:
var reader = parent.CreateReader();
reader.MoveToContent();
return reader.ReadInnerXml();
总有串联:
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.加入上阵列:
return String.Join("", parent.Nodes().Select(x => x.ToString()).ToArray());
String.Concat上阵列:
return String.Concat(parent.Nodes().Select(x => x.ToString()).ToArray());
我还没有显示"普通老System.Xml"算法在这里,因为它只呼吁。InnerXml上的节点。
结论
如果业绩是重要的(例如很多XML,分析经常),我会 使用丹尼尔的 CreateReader
方法每一次.如果你只是在做一些疑问,你可能会想到使用麦克的更简明的总的方法。
如果你使用XML在大要素有很多的节点(也许100人),你可能开始看到有益的使用 StringBuilder
通过综合方法,但没有结束 CreateReader
.我不认为 Join
和 Concat
方法将永远是更有效地在这些条件,因为罚款的转换一个大型的表大阵列(即使很明显在这里用较小的清单)。
其他提示
我认为这是一个更好的方法(在VB,不应该将难以翻译):
给出一个T x:
Dim xReader = x.CreateReader
xReader.MoveToContent
xReader.ReadInnerXml
关于如何使用这种"扩展"的方法上T?为我工作!
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();
}
注意到:代码以上已经使用 element.Nodes()
作为反对 element.Elements()
.非常重要的是要记住两者之间的区别. element.Nodes()
给你一切都喜欢 XText
, XAttribute
等等,但是 XElement
只有一个元素。
与所有因信用那些发现和证明的最佳做法(谢谢), 在这里,它被裹在一个扩展方法:
public static string InnerXml(this XNode node) {
using (var reader = node.CreateReader()) {
reader.MoveToContent();
return reader.ReadInnerXml();
}
}
保持它的简单和有效力:
String.Concat(node.Nodes().Select(x => x.ToString()).ToArray())
- 总是存和业绩的效率低下的时连字符串
- 使用加入("",sth)是使用两倍大串列于Concat...看起来很奇怪的代码。
- 使用+=看起来很奇怪,但显然不是更糟糕于使用'+'-可能会被优化,以同样的代码,因为分配结果是未使用,并且可能安全地删除,通过编译器。
- StringBuilder是如此迫切和大家都知道,不必要的"国家"吸。
我最终使用这样的:
Body = t.Element("body").Nodes().Aggregate("", (b, node) => b += node.ToString());
就个人而言,我最后写 InnerXml
扩展方法的使用的总的方法:
public static string InnerXml(this XElement thiz)
{
return thiz.Nodes().Aggregate( string.Empty, ( element, node ) => element += node.ToString() );
}
我的客户代码然后只作简短的,因为它是旧的System.Xml 名字空间:
var innerXml = myXElement.InnerXml();
@格雷格:看来你已经编辑了你的回答是一个完全不同的回答。我的答案是肯定的,我可以这样做使用System.Xml 但是希望能得到我脚的湿与皇宫于XML。
我会离开我原来的答复以下情况下任何其他人想知道为什么我不能只使用T。值的财产得到什么我需要:
@格雷格:值的财产将连接所有文本内容的任何儿童的节点。所以如果体元件只包含的文本,它的工作原理,但如果它包含XHTML我得到的所有文本连接在一起,但没有标记。
//使用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);
医生。ToString()或医生。ToString(SaveOptions)做的工作。看看 http://msdn.microsoft.com/en-us/library/system.xml.linq.xelement.tostring(v=与110).aspx
它是能够使用System.Xml 名字空间物体得到工作完成在这里而不是使用皇宫?因为你已经提到的,XmlNode.InnerXml正是你需要什么。
想知道,如果(通知我得到了摆脱的b+=,只是有b+)
t.Element( "body" ).Nodes()
.Aggregate( "", ( b, node ) => b + node.ToString() );
可能略低有效比
string.Join( "", t.Element.Nodes()
.Select( n => n.ToString() ).ToArray() );
不是100%肯定...但一眼Aggregate()和串。Join()在反射...我 想想 我读了它作为集合体只是附加一个回价值,因此基本上获得:
string=string+字符串
与串。加入,就有一些提及在那里的FastStringAllocation或什么东西,让我事情的人在微软可能已经把一些额外的性能,提高在那里。当然我的。ToArray()呼唤我否定这一点,但是我只是想提供了另一个建议。
你知道吗?最好的事情要做的就是回到CDATA:(im在寻找解决方案在这里,但我认为CDATA是迄今为止最简单和便宜的,没有最方便的开发与。
var innerXmlAsText= XElement.Parse(xmlContent)
.Descendants()
.Where(n => n.Name.LocalName == "template")
.Elements()
.Single()
.ToString();
会为你做这份工作
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();
}