.Net Xml反序列化 - 支持多个命名空间

时间:2010-06-23 21:15:15

标签: .net serialization xml-serialization

我需要支持两个非常相似但不同的xml文件的XML反序列化。

文件1:

<?xml version="1.0" encoding="UTF-8"?>
<lr:LogReport xmlns:dcml="http://www.x1.org/schemas/Types/"
    xmlns:ds="http://www.x3.org/2000/09/xmldsig#"
    xmlns:lr="http://www.x.org/schemas/LogRecord/"
    xmlns:xs="http://www.x3.org/2001/XMLSchema"
    xmlns:xsi="http://www.x3.org/2001/XMLSchema-instance">
    <lr:reportDate>2010-03-05T07:00:52-08:00</lr:reportDate>

文件2:

<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<LogReport xmlns="http://www.x.org/schemas/LogRecord" 
    xmlns:dcml="http://www.x1.org/schemas/Types" 
    xmlns:ds="http://www.x3.org/2000/09/xmldsig#" 
    xmlns:lr="http://www.x.org/schemas/LogRecord" 
    xmlns:xs="http://www.x3.org/2001/XMLSchema" 
    xmlns:xsi="http://www.x3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.x.org/schemas/LogRecord ./LogRecord.xsd  http://www.x1.org/schemas/Types ./Types.xsd">
    <lr:reportDate>2010-02-26T07:00:02-08:00</lr:reportDate>

班级定义:

<System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.42"), _
 System.SerializableAttribute(), _
 System.Diagnostics.DebuggerStepThroughAttribute(), _
 System.ComponentModel.DesignerCategoryAttribute("code"), _
 System.Xml.Serialization.XmlTypeAttribute([Namespace]:="http://www.smpte-ra.org/schemas/430-4/2008/LogRecord"), _
 System.Xml.Serialization.XmlRootAttribute("LogReport", [Namespace]:="http://www.smpte-ra.org/schemas/430-4/2008/LogRecord", IsNullable:=False)> _
Partial Public Class LogReport

匹配File1的文件在匹配File2的文件成功时失败。关键区别在于两个命名空间定义的尾部斜杠。

代码示例:

Dim oLogReport As New LogReport
Dim oType As System.Type = oLogReport.GetType
Dim oReader As System.Xml.XmlReader = Nothing
Dim oSerializer As New XmlSerializer(oType)
oReader = System.Xml.XmlReader.Create(sFileName)
oLogReport = CType(oSerializer.Deserialize(oReader), LogReport)

File1出错:

{"<LogReport xmlns='http://www.x.org/schemas/LogRecord/'> was not expected."}

已经尝试过:How do I specify XML serialization attributes to support namespace prefixes during deserialization in .NET?

这些文件来自第三方,因此无法更改序列化过程。有没有办法支持这两种xml格式?我需要两个单独的课程吗?

谢谢!

3 个答案:

答案 0 :(得分:2)

两个独立的班级模型是一个选项,虽然不是一个很好的选择。

您是否真的将这些文件作为XML然后在代码中处理,或者您是否正在使用应该自动反序列化XML的smoe类代理?

如果您正在进行自己的反序列化,我会考虑在执行反序列化之前创建一个简单的XSL转换来转换内存中的命名空间。用另一对简单地替换一对名称空间的转换将非常简短。

答案 1 :(得分:1)

到处尝试另外一个修复,因为我不喜欢做一个发现&amp;在xml文件中替换。

所以这是 - 我的机器上的工作 -

我首先使用 xsd.exe 生成了logRecordTypelogRecordHeaderType类。请注意,我只需要解析logRecordHeader元素,因此这里有一些额外的工作。但修复基本上是使用FixupNameTable,以便每次出现带有尾部斜杠的命名空间都替换为没有它的那个。

namespace DolbyService.Schemas
{
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

public partial class logRecordType
{
    public const string xmlns_lr = "http://www.smpte-ra.org/schemas/430-4/2008/LogRecord";
    public const string xmlns_dcml = "http://www.smpte-ra.org/schemas/433/2008/dcmlTypes";


    public static IEnumerable<logRecordHeaderType> Parse(Stream xmlfile)
    {
        XmlReaderSettings settings = new XmlReaderSettings();
        settings.NameTable = new FixupNameTable();
        using (var rdr = XmlReader.Create(xmlfile, settings))
        {
            var headerSerialize = new XmlSerializer(typeof(logRecordHeaderType));

            while (rdr.ReadToFollowing(logRecordHeaderType.LogRecordHeader, logRecordType.xmlns_lr))
            {
                using (var subreader = rdr.ReadSubtree())
                {
                    var ok = headerSerialize.CanDeserialize(subreader);
                    var logRecordHeader = headerSerialize.Deserialize(subreader);
                    yield return logRecordHeader as logRecordHeaderType;
                }
            }
        }
    }
}

internal class FixupNameTable : XmlNameTable
{
    private NameTable _table = new NameTable();

    public override string Add(string key)
    {
        key = ReplaceKey(key);
        return _table.Add(key);
    }

    private static string ReplaceKey(string key)
    {
        if (key.StartsWith(logRecordType.xmlns_lr)) key = logRecordType.xmlns_lr;
        if (key.StartsWith(logRecordType.xmlns_dcml)) key = logRecordType.xmlns_dcml;
        return key;
    }

    public override string Add(char[] array, int offset, int length)
    {
        return _table.Add(array, offset, length);
    }

    public override string Get(string key)
    {
        key = ReplaceKey(key);
        return _table.Get(key);
    }

    public override string Get(char[] array, int offset, int length)
    {
        return _table.Get(array, offset, length);
    }
}

[XmlRoot(logRecordHeaderType.LogRecordHeader, Namespace = logRecordType.xmlns_lr, IsNullable = false)]
public partial class logRecordHeaderType
{
    public const string LogRecordHeader = "LogRecordHeader";

    private static XmlSerializer _ser = new XmlSerializer(typeof(logRecordHeaderType));

    public static logRecordHeaderType Deserialize(XmlReader xmlReader)
    {
        return _ser.Deserialize(xmlReader) as logRecordHeaderType;
    }

    public static bool CanDeserialize(XmlReader xmlReader)
    {
        return _ser.CanDeserialize(xmlReader);
    }
}

public class HeaderComparer : IEqualityComparer<logRecordHeaderType>
{
    public bool Equals(logRecordHeaderType x, logRecordHeaderType y)
    {
        return x.EventID == y.EventID;
    }

    public int GetHashCode(logRecordHeaderType obj)
    {
        return obj.EventID.GetHashCode();
    }
}
}

答案 2 :(得分:0)

如果名称空间不同,那么XML就不同了。