如何创建忽略命名空间但不检查字符的XmlTextReader

时间:2015-02-05 09:00:15

标签: c# xml

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

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

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

使用基类Create()的静态方法XmlReader我可以传入XmlReaderSettings,但该方法返回XmlTextReaderImpl并且没有属性{{1设置并且无法转换为Namespace

XmlTextReader

那么如何创建这样的XmlTextReader呢?它甚至可能吗? var settings = new XmlReaderSettings { CheckCharacters = false}; var reader = XmlTextReader.Create(gzs, settings); XmlTextReader textReader = reader as XmlTextReader // not possible 上是否有任何属性可以忽略命名空间?

2 个答案:

答案 0 :(得分:2)

这并不难。

我的任务是反序列化相同结构的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;

答案 1 :(得分:0)

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

响应基本上是相同的,但是响应中的根名称空间根据传递给服务的凭据而有所不同。

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

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

在我的情况下,replaceNs参数是通过反射从类型的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;
    }
}