使用DataContractSerializer仅反序列化XML文档的一部分

时间:2016-04-24 20:11:05

标签: c# xml linq deserialization datacontractserializer

假设我有一个导出(序列化)功能,可执行以下操作

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
因为读到文件末尾将导致它尝试反序列化结束&lt; / Entries&gt;标记为条目。

这些方法所属的类将作为我们的SCCM操作系统部署任务序列的一部分使用,这意味着它们可以被多个同时运行的任务序列使用,这些任务序列通过网络查询源XML文件。所以我有点担心更好的表现。

我是在追逐我的尾巴尝试使用单个XmlReader执行此操作,还是将LINQ to XML与单独的XmlReader结合使用是最佳选择?

2 个答案:

答案 0 :(得分:1)

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);
        // ...
    }
}

此外,此代码在两种情况下都能正常工作。

答案 1 :(得分:0)

如果您的转换足够规则,那么进行XSLT转换并将其应用于源文档将是我采取的方法。您可以创建xml或非xml输出。如果您从未使用它,那有点奇怪......但是您编写了xsl:apply-template元素来选择输入,然后嵌套 Application.Run(loginForm); if (loginForm.IsLoggedIn == true) { ERS_FDData.ERSUser user = loginForm.user; loginForm.Close(); Application.Run(new frmMain(loginForm.user)); } else Application.Exit(); 元素来描述如何转换所选部分。为您的问题定制的声音。

一个很好的例子,在相关的问题中可以找到MPI_MAXLOC,以及使用XSLT here的50,000英尺概述。