从XML网络流中读取整个元素
本文关键字:元素 读取 XML 网络 | 更新日期: 2023-09-27 18:25:21
我正在用C#.NET 4.0编写一个网络服务器。有一个网络TCP/IP连接,我可以通过它接收完整的XML元素。它们定期到达,我需要立即处理它们。每个XML元素本身就是一个完整的XML文档,因此它有一个开始元素、几个子节点和一个结束元素。整个流没有一个根元素。所以当我打开连接时,我得到的是这样的:
<status>
<x>123</x>
<y>456</y>
</status>
一段时间后,它继续:
<status>
<x>234</x>
<y>567</y>
</status>
等等。我需要一种方法来读取完整的XML字符串,直到状态元素完成为止。我不想用纯文本阅读方法这样做,因为我不知道数据的格式。我决不能像其他地方经常描述的那样,等到整个流程结束。我尝试过使用XmlReader类,但它的文档很奇怪,方法不起作用,第一个元素丢失,在发送第二个元素后,会发生XmlException,因为有两个根元素。
试试这个:
var settings = new XmlReaderSettings
{
ConformanceLevel = ConformanceLevel.Fragment
};
using (var reader = XmlReader.Create(stream, settings))
{
while (!reader.EOF)
{
reader.MoveToContent();
var doc = XDocument.Load(reader.ReadSubtree());
Console.WriteLine("X={0}, Y={1}",
(int)doc.Root.Element("x"),
(int)doc.Root.Element("y"));
reader.ReadEndElement();
}
}
如果将"一致性级别"更改为"片段",则它可能与XmlReader
一起工作。
这是MSDN中的一个(略有修改)示例:
XmlReaderSettings settings = new XmlReaderSettings();
settings.ConformanceLevel = ConformanceLevel.Fragment;
XmlReader reader = XmlReader.Create(streamOfXmlFragments, settings);
您可以使用XElement.Load
,它更适用于.net 3.5中新增的Xml元素片段的流式传输,还支持直接从流中读取。
看看System.Xml.Linq
我认为您可能仍然需要添加一些控制逻辑,以便对您正在接收的消息进行分区,但您也可以尝试一下。
我不确定是否有任何内置的东西可以做到这一点。我打开一个字符串生成器,填充它,直到看到</status>
标记,然后使用普通的XmlDocument解析它。
与dtb的解决方案没有实质性区别,但linqier
static IEnumerable<XDocument> GetDocs(Stream xmlStream)
{
var xmlSettings = new XmlReaderSettings() { ConformanceLevel = ConformanceLevel.Fragment };
using (var xmlReader = XmlReader.Create(xmlStream, xmlSettings))
{
var xmlPathNav = new XPathDocument(xmlReader).CreateNavigator();
foreach (var selectee in xmlPathNav.Select("/*").OfType<XPathNavigator>())
yield return XDocument.Load(selectee.ReadSubtree());
}
}
我在PowerShell中遇到了类似的问题,但提问者的问题是在C#中,所以我尝试翻译它(并验证它是否有效)。这是我发现的线索,它让我度过了最后的小颠簸("…XPathDocument发挥其魔力的方式是创建一个"透明"的根节点,并保存其中的片段。我说它是透明的,因为您的XPath查询可以使用根节点轴,并且仍然可以正确地解析为片段…")
我正在处理的XML片段恰好很小。如果你有更大的块,你可能想研究XStreamingElement——它可以增加很多复杂性,但在处理大量XML时也会大大减少内存使用。