我可以让 XmlSerializer 在反序列化时忽略命名空间吗?

Posted

技术标签:

【中文标题】我可以让 XmlSerializer 在反序列化时忽略命名空间吗?【英文标题】:Can I make XmlSerializer ignore the namespace on deserialization? 【发布时间】:2010-10-26 14:21:42 【问题描述】:

我是否可以让 XmlSerializer 在反序列化时忽略名称空间(xmlns 属性),这样无论是否添加该属性或即使该属性是伪造的都无关紧要?我知道来源将始终受到信任,所以我不关心 xmlns 属性。

【问题讨论】:

小心,如果你覆盖NamespaceURI,它不仅会影响所有元素,还会影响属性。有时这会导致反序列化器忽略将它们全部设置为 null 的属性。 显然存在忽略命名空间的缺陷。你可以对元素说同样的话——如果反序列化程序需要一个命名空间限定的元素,并且在没有命名空间的元素中找到一个元素,那么它不会在反序列化的实例中设置关联的属性。这些只是道路规则。它在我给出的示例中有效,因为所有元素都没有命名空间。 【参考方案1】:

是的,您可以告诉 XmlSerializer 在反序列化期间忽略命名空间。

定义一个忽略命名空间的 XmlTextReader。像这样:

// helper class to ignore namespaces when de-serializing
public class NamespaceIgnorantXmlTextReader : XmlTextReader

    public NamespaceIgnorantXmlTextReader(System.IO.TextReader reader): base(reader)  

    public override string NamespaceURI
    
        get  return ""; 
    


// helper class to omit XML decl at start of document when serializing
public class XTWFND  : XmlTextWriter 
    public XTWFND (System.IO.TextWriter w) : base(w)  Formatting= System.Xml.Formatting.Indented;
    public override void WriteStartDocument ()  

这是一个如何使用 TextReader 进行反序列化的示例:

public class MyType1 

    public string Label
    
        set   _Label= value;  
        get  return _Label;  
    

    private int _Epoch;
    public int Epoch
    
        set   _Epoch= value;  
        get  return _Epoch;  
            




    String RawXml_WithNamespaces = @"
      <MyType1 xmlns='urn:booboo-dee-doo'>
        <Label>This document has namespaces on its elements</Label>
        <Epoch xmlns='urn:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'>0</Epoch>
      </MyType1>";


    System.IO.StringReader sr;
    sr= new System.IO.StringReader(RawXml_WithNamespaces);
    var s1 = new XmlSerializer(typeof(MyType1));
    var o1= (MyType1) s1.Deserialize(new NamespaceIgnorantXmlTextReader(sr));
    System.Console.WriteLine("\n\nDe-serialized, then serialized again:\n");
    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
    ns.Add("urn", "booboo-dee-doo");
    s1.Serialize(new XTWFND(System.Console.Out), o1, ns);
    Console.WriteLine("\n\n");

结果是这样的:

    <MyType1>
      <Label>This document has namespaces on its elements</Label>
      <Epoch>0</Epoch>
    </MyType1>

【讨论】:

注意这是我的意思。您不是在告诉 XmlSerializer 忽略名称空间 - 您是在给它提供没有名称空间的 XML。 ???我不明白。我给了它在元素上具有名称空间的 XML。代码反序列化(读取)XML 文档并忽略命名空间。【参考方案2】:

扩展 Wolfgang Grinfeld 答案(无异常处理):

public static Message Convert(XmlDocument doc)

    Message obj;
    using (TextReader textReader = new StringReader(doc.OuterXml))
    
        using (XmlTextReader reader = new XmlTextReader(textReader))
        
            reader.Namespaces = false;
            XmlSerializer serializer = new XmlSerializer(typeof(Message));
            obj = (Message)serializer.Deserialize(reader);
        
    

    return obj;

【讨论】:

它并没有真正忽略。如果设置为 false,则要求您不包含命名空间。 这对我很有效。我的用例是在反序列化为对象时忽略在 XML 文档中收到的命名空间,这样无论命名空间是否存在,行为都是一致的。谢谢。【参考方案3】:

如果你期望没有命名空间,但输入有命名空间,那么你可以设置

命名空间 = 假

在您的 XmlTextReader 上。

【讨论】:

【参考方案4】:

这不会忽略命名空间,而是期望它。我试图做和你一样的事情,但我已经使用 XSD 添加了验证,现在需要命名空间。所以这就是我以前期望的命名空间。 https://***.com/a/7730989/1856992

【讨论】:

【参考方案5】:

通过使用 XmlSerializer Deserialize 从 xml 而不是从流中读取来解决此问题。这种方式在 xml 被反序列化之前,使用 Regex 从 xml 中删除 xsi:type。这样做是跨平台的可移植类库,所以没有很多其他选择:(。在此之后反序列化似乎工作正常。

以下代码可以提供帮助,

public static TClass Deserialize<TClass>(string xml) where TClass : class, new()

    var tClass = new TClass();

    xml = RemoveTypeTagFromXml(xml);

    var xmlSerializer = new XmlSerializer(typeof(TClass));
    using (TextReader textReader = new StringReader(xml))
    
        tClass = (TClass)xmlSerializer.Deserialize(textReader);
    
    return tClass;


public static string RemoveTypeTagFromXml(string xml)

    if (!string.IsNullOrEmpty(xml) && xml.Contains("xsi:type"))
    
        xml = Regex.Replace(xml, @"\s+xsi:type=""\w+""", "");
    
    return xml;

【讨论】:

可以将命名空间通知给XmlSerializer,所以不需要从XML中移除: XmlSerializer serializer = new XmlSerializer(typeof(T), elementXml.GetDefaultNamespace().NamespaceName); return (T)serializer.Deserialize(elementXml.CreateReader());【参考方案6】:

为什么要让 XmlSerializer 忘记 XML 的工作原理? XML 的一个事实是,两个具有相同名称但不同命名空间的元素是不同的元素。

如果你想处理没有命名空间的 XML,那么你应该预处理它以移除命名空间,然后然后将它传递给序列化器。

【讨论】:

约翰,你说的是真的,但是,你有时会从那些认为 xml 只是格式很好的数据后面的开始标签 .. 使用尖括号的结束标签样式的人那里得到“xml”数据;他们完全没有注意到整个命名空间概念;我的猜测是,NotDan 是那些需要使用这类人提供的 xml 数据的可怜人之一。我经历过something similar. @John:有时你必须选择你的战斗。对一些相对琐碎的事情说“不”,客户说“如果你做不到,还有很多其他人可以做到。Hasta la vista,宝贝!”。我们可以指出潜在的问题,但最终是他们的决定和决定。如果我们想保持他们的业务,我们必须尊重该决定并解决它。 @simon 这种态度是导致问题持续存在的原因,即使在七年后也是如此。我应该说“不,但我们很乐意帮助您学习生成有效的 XML”。 @John,是的,除非您必须与 zml 交互,否则您无法控制。请告诉 UPS、FedEx 和 USPS 修复其损坏的 Web 服务。我会喜欢的。 让我重申最后一段。与其让所有的“xml 程序”都处理不同的非 XML 语言,不如使用预处理器。这将使您的源代码的疯狂与您的程序员隔离开来,他们将能够使用标准 XML API 来处理 XML。

以上是关于我可以让 XmlSerializer 在反序列化时忽略命名空间吗?的主要内容,如果未能解决你的问题,请参考以下文章

在 xml 序列化期间忽略属性,但在反序列化期间不忽略

无法使用 c# xmlserializer 反序列化以前序列化的 XML

如何让 XmlSerializer 将布尔值编码为是/否?

XmlSerializer 在文件中加载“作为”反序列化期间 - 当 XML 包含希伯来语时

XMLSerializer 不反序列化 XML

在反序列化时使用动态和强制执行 WCF 合同