使用 DataContractSerializer 仅反序列化 XML 文档的一部分
Use DataContractSerializer to Deserialize only part of an XML document
假设我有一个执行以下操作的导出(序列化)函数
public void ExportToXML()
{
var DCS = new DataContractSerializer(typeof(Entry));
var XWriter = XmlWriter.Create(@"C:\Temp\Export.xml");
XWriter.WriteStartDocument();
XWriter.WriteStartElement("Entries");
Entries.ForEach(e =>
{
DCS.WriteStartObject(XWriter, e);
DCS.WriteObjectContent(XWriter, e);
DCS.WriteEndObject(XWriter);
});
XWriter.WriteEndElement();
XWriter.WriteEndDocument();
XWriter.Close();
}
导出一个看起来像
的 XML 文件
<Entries>
<Entry>{Some Data}</Entry>
<Entry>{Some Data}</Entry>
<Entry>{Some Data}</Entry>
<Entry>{Some Data}</Entry>
</Entries>
对于 Import 方法,我想一次反序列化每个
<Entry>{Some Data}</Entry>
一个,以便我可以应用转换
Func<Entry,Entry>
如果一个
Func<Entry,bool>
谓词为真
这是我想出来的
public void ImportFromXML(string FileName, Func<Entry,Entry> Transform, Func<Entry,bool> DoTransform)
{
var DCS = new DataContractSerializer(typeof(Entry));
var ImportedEntries = new List<Entry>();
foreach (var EntryElement in XDocument.Load(FileName).Root.Elements().Where(xe => xe.Name.LocalName == "Entry"))
{
var XMLEntry = (Entry)DCS.ReadObject(EntryElement.CreateReader());
ImportedEntries.Add(DoTransform(XMLEntry) ? Transform(XMLEntry) : XMLEntry);
}
entries = ImportedEntries.ToDictionary(e => e.KeyName + "\" + e.ValueName);
}
这可行,但我想知道是否有一种方法可以使用单个 XmlReader 一次性完成此操作,而不是生成每个 XElement 的 XMLReader。
我试图反转导出方法的逻辑
public void ImportFromXML(string FileName, Func<Entry,Entry> Transform, Func<Entry,bool> DoTransform)
{
var DCS = new DataContractSerializer(typeof(Entry));
var ImportedEntries = new List<Entry>();
var XReader = XmlReader.Create(@"C:\Temp\Export.xml");
XReader.ReadStartElement("Entries");
while (!{WHAT Exit Condition?})
{
var XMLEntry = (Entry)DCS.ReadObject(XReader());
ImportedEntries.Add(DoTransform(XMLEntry) ? Transform(XMLEntry) : XMLEntry);
}
XReader.Close();
entries = ImportedEntries.ToDictionary(e => e.KeyName + "\" + e.ValueName);
}
但是我不确定要为
{WHAT Exit Condition?}
添加什么,显然我不能使用
!XReader.EOF
因为读到文件末尾会导致它尝试反序列化结束 标记作为条目。
class 这些方法的一部分将作为我们的 SCCM OS 部署任务序列的一部分使用,这意味着它们可以被多个并发 运行 任务序列使用正在通过网络查询源 XML 文件。所以我有点担心更好的性能。
我是在追着我的尾巴尝试使用单个 XmlReader 执行此操作,还是将 LINQ to XML 与单独的 XmlReader 结合使用是最佳选择?
如果您的转换足够规则,我将采用 XSLT 转换并将其应用于源文档的方法。您可以制作 xml 或非 xml 输出。如果您从未使用过它,那就有点奇怪了……但是您编写了 xsl:template
个元素 select 输入,然后嵌套 xsl:apply-template
个描述如何转换 selected 的元素件。听起来是为您的问题量身定制的。
一个不错的例子,在相关问题中可以找到here, and a good 50,000 ft overview of using XSLT here。
XML文件可以写有缩进和无缩进。在前一种情况下,以下代码可以正常工作:
var settings = new XmlWriterSettings { Indent = true };
var DCS = new DataContractSerializer(typeof(Entry));
using (var writer = XmlWriter.Create(fileName, settings)) // with indentation
{
writer.WriteStartDocument();
writer.WriteStartElement("Entries");
foreach (var entry in Entries)
{
DCS.WriteObject(writer, entry);
}
}
using (var reader = XmlReader.Create(fileName))
{
while (reader.ReadToFollowing("Entry"))
{
var xmlEntry = (Entry)DCS.ReadObject(reader);
// ...
}
}
在这种情况下,ReadToFollowing
方法首先读取空格,然后前进到下一个Entry
节点。但是在没有缩进的情况下,该方法会跳过一个 Entry
节点。
对于后一种情况,我们可以使用如下代码:
using (var writer = XmlWriter.Create(fileName)) // without indentation
// ...
using (var reader = XmlReader.Create(fileName))
{
while (reader.LocalName == "Entry" || reader.ReadToFollowing("Entry"))
{
var xmlEntry = (Entry)DCS.ReadObject(reader);
// ...
}
}
此外,这段代码在这两种情况下都能正常工作。
假设我有一个执行以下操作的导出(序列化)函数
public void ExportToXML()
{
var DCS = new DataContractSerializer(typeof(Entry));
var XWriter = XmlWriter.Create(@"C:\Temp\Export.xml");
XWriter.WriteStartDocument();
XWriter.WriteStartElement("Entries");
Entries.ForEach(e =>
{
DCS.WriteStartObject(XWriter, e);
DCS.WriteObjectContent(XWriter, e);
DCS.WriteEndObject(XWriter);
});
XWriter.WriteEndElement();
XWriter.WriteEndDocument();
XWriter.Close();
}
导出一个看起来像
的 XML 文件<Entries>
<Entry>{Some Data}</Entry>
<Entry>{Some Data}</Entry>
<Entry>{Some Data}</Entry>
<Entry>{Some Data}</Entry>
</Entries>
对于 Import 方法,我想一次反序列化每个
<Entry>{Some Data}</Entry>一个,以便我可以应用转换
Func<Entry,Entry>
如果一个
Func<Entry,bool>
谓词为真
这是我想出来的
public void ImportFromXML(string FileName, Func<Entry,Entry> Transform, Func<Entry,bool> DoTransform)
{
var DCS = new DataContractSerializer(typeof(Entry));
var ImportedEntries = new List<Entry>();
foreach (var EntryElement in XDocument.Load(FileName).Root.Elements().Where(xe => xe.Name.LocalName == "Entry"))
{
var XMLEntry = (Entry)DCS.ReadObject(EntryElement.CreateReader());
ImportedEntries.Add(DoTransform(XMLEntry) ? Transform(XMLEntry) : XMLEntry);
}
entries = ImportedEntries.ToDictionary(e => e.KeyName + "\" + e.ValueName);
}
这可行,但我想知道是否有一种方法可以使用单个 XmlReader 一次性完成此操作,而不是生成每个 XElement 的 XMLReader。
我试图反转导出方法的逻辑
public void ImportFromXML(string FileName, Func<Entry,Entry> Transform, Func<Entry,bool> DoTransform)
{
var DCS = new DataContractSerializer(typeof(Entry));
var ImportedEntries = new List<Entry>();
var XReader = XmlReader.Create(@"C:\Temp\Export.xml");
XReader.ReadStartElement("Entries");
while (!{WHAT Exit Condition?})
{
var XMLEntry = (Entry)DCS.ReadObject(XReader());
ImportedEntries.Add(DoTransform(XMLEntry) ? Transform(XMLEntry) : XMLEntry);
}
XReader.Close();
entries = ImportedEntries.ToDictionary(e => e.KeyName + "\" + e.ValueName);
}
但是我不确定要为
{WHAT Exit Condition?}添加什么,显然我不能使用
!XReader.EOF因为读到文件末尾会导致它尝试反序列化结束 标记作为条目。
class 这些方法的一部分将作为我们的 SCCM OS 部署任务序列的一部分使用,这意味着它们可以被多个并发 运行 任务序列使用正在通过网络查询源 XML 文件。所以我有点担心更好的性能。
我是在追着我的尾巴尝试使用单个 XmlReader 执行此操作,还是将 LINQ to XML 与单独的 XmlReader 结合使用是最佳选择?
如果您的转换足够规则,我将采用 XSLT 转换并将其应用于源文档的方法。您可以制作 xml 或非 xml 输出。如果您从未使用过它,那就有点奇怪了……但是您编写了 xsl:template
个元素 select 输入,然后嵌套 xsl:apply-template
个描述如何转换 selected 的元素件。听起来是为您的问题量身定制的。
一个不错的例子,在相关问题中可以找到here, and a good 50,000 ft overview of using XSLT here。
XML文件可以写有缩进和无缩进。在前一种情况下,以下代码可以正常工作:
var settings = new XmlWriterSettings { Indent = true };
var DCS = new DataContractSerializer(typeof(Entry));
using (var writer = XmlWriter.Create(fileName, settings)) // with indentation
{
writer.WriteStartDocument();
writer.WriteStartElement("Entries");
foreach (var entry in Entries)
{
DCS.WriteObject(writer, entry);
}
}
using (var reader = XmlReader.Create(fileName))
{
while (reader.ReadToFollowing("Entry"))
{
var xmlEntry = (Entry)DCS.ReadObject(reader);
// ...
}
}
在这种情况下,ReadToFollowing
方法首先读取空格,然后前进到下一个Entry
节点。但是在没有缩进的情况下,该方法会跳过一个 Entry
节点。
对于后一种情况,我们可以使用如下代码:
using (var writer = XmlWriter.Create(fileName)) // without indentation
// ...
using (var reader = XmlReader.Create(fileName))
{
while (reader.LocalName == "Entry" || reader.ReadToFollowing("Entry"))
{
var xmlEntry = (Entry)DCS.ReadObject(reader);
// ...
}
}
此外,这段代码在这两种情况下都能正常工作。