【问题标题】:How do I create a XmlTextReader that ignores Namespaces and does not check characters如何创建忽略命名空间且不检查字符的 XmlTextReader
【发布时间】:2015-04-05 01:30:44
【问题描述】:

我想使用一个XmlTextReader 忽略命名空间并且不检查字符。要忽略命名空间,我可以设置属性Namespaces=false 并且不检查字符我可以使用XmlReaderSettings.CheckCharacters = false

我尝试使用它的构造函数创建XmlTextReader,但这不允许我传入配置的XmlReaderSettings。属性Settings 是只读的,所以我无法在构造后设置它。

XmlTextReader reader = new XmlTextReader(gzs) { Namespaces = false};
reader.Settings = new XmlReaderSettings { CheckCharacters = false}; // readonly

使用基类XmlReader 的静态方法Create() 我可以传入XmlReaderSettings,但是该方法返回一个XmlTextReaderImpl,并且没有要设置的属性Namespace,它不能被强制转换为XmlTextReader.

var settings = new XmlReaderSettings { CheckCharacters = false}; 
var reader = XmlTextReader.Create(gzs, settings); 
XmlTextReader textReader = reader as XmlTextReader  // not possible

那么如何创建这样的 XmlTextReader?甚至可能吗? XmlReaderSettings 上是否有任何属性可以忽略命名空间?

【问题讨论】:

    标签: c# xml


    【解决方案1】:

    没那么难。

    我的任务是反序列化相同结构的 xml 文件,可以有或没有默认命名空间声明。

    首先,我使用 XmlTextReader 解决方案找到了这个 discussion:NamespaceIgnorantXmlTextReader。 但 MSDN 建议不要使用 XmlTextReader,而是使用 XmlReader。

    所以我们需要在 XmlReader 上做同样的事情。

    XmlReader 是一个抽象类,我们需要先做一个包装器。 Here 是一篇很好的文章如何做到这一点。而here 是一个现成的 XmlWrappingReader。

    然后我们需要扩展它:

    public class XmlExtendableReader : XmlWrappingReader
    {
        private bool _ignoreNamespace { get; set; }
    
        public XmlExtendableReader(TextReader input, XmlReaderSettings settings, bool ignoreNamespace = false)
        : base(XmlReader.Create(input, settings))
        {
            _ignoreNamespace = ignoreNamespace;
        }
    
        public override string NamespaceURI
        {
            get
            {
                return _ignoreNamespace ? String.Empty : base.NamespaceURI;
            }
        }
    }
    

    就是这样。现在我们可以使用它来控制 XmlReaderSettings 和命名空间处理:

    XmlReaderSettings settings = new XmlReaderSettings()
    {
        CheckCharacters = false,
        ConformanceLevel = ConformanceLevel.Document,
        DtdProcessing = DtdProcessing.Ignore,
        IgnoreComments = true,
        IgnoreProcessingInstructions = true,
        IgnoreWhitespace = true,
        ValidationType = ValidationType.None
    };
    
    using (XmlExtendableReader xmlreader = new XmlExtendableReader(reader, settings, true))
        _entities = ((Orders)_serializer.Deserialize(xmlreader)).Order;
    

    【讨论】:

      【解决方案2】:

      就我而言,作为提供商的 api 版本控制策略的一部分,我遇到了在使用 XmlSerializer 反序列化到同一个 C# 类的同时支持不同响应命名空间的需求。

      响应基本相同,但响应中的根命名空间因传递给服务的凭据而异。

      因此,我使用 XmlWrappingReader 方法将服务返回的命名空间重命名为 C# 类通过 XmlTypeAttribute 附加的命名空间。

      但只有一个警告:使用字符串交互,因为我怀疑 XmlSerializer 在从 XmlReader 读取以匹配 c# 类中的目标命名空间时正在使用 Object.ReferenceEquals。

      在我的例子中,replacementNs 参数是通过反射从类型的 XmlTypeAttribute 获得的,并且显然与 XmlSerializer 内部使用的字符串不是完全相同的对象引用。

      因为这件傻事,我差点掉头发……

      public class ReplaceNsXmlReader : XmlWrappingReader
      {
          private readonly string replacementNs;
      
          public ReplaceNsXmlReader(XmlReader reader, string replacementNs)
              : base(reader)
          {
              //
              // NOTE: String.Intern is here needed for the XmlSerializer
              // that will be using this reader to deserialize correctly
              //
      
              this.replacementNs = String.Intern(replacementNs);
          }
      
          public override string NamespaceURI
          {
              get => replacementNs;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-12-05
        • 2015-02-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-30
        • 2011-05-25
        相关资源
        最近更新 更多