XmlValidatingReader问题超过派生的XmlReaders

This whole validation ickiness deserved two posts, so I didn't mention it in the last XmlValidatingReader post.

整个验证问题应该得到两篇文章,因此我在上一则XmlValidatingReader文章中没有提及。

The XML format that I'm parsing and validating isn't the savvyest of formats as it was created years ago before the XML Schema specification was complete. While it has a namespace and it's an official specification, the instance documents don't have a namespace. They are entirely "unqualified." So, basically I'm trying to validate XML documents with a namespace against a schema that expects namespaces.

我正在解析和验证的XML格式并不是最聪明的格式,因为它是几年前在XML Schema规范完成之前创建的。 尽管它具有名称空间并且是官方规范,但是实例文档没有名称空间。 他们完全是“不合格”。 因此,基本上,我正在尝试根据需要名称空间的模式验证具有名称空间的XML文档。

Additionally, the elementFormDefault is set to "unqualified." There's a great explanation of what elementFormDefault means here.

此外,elementFormDefault设置为“不合格”。 这里对elementFormDefault的含义有很好的解释。

The documents come in like this:

这些文档如下所示:

<FOO>
  <BAR>text</BAR>
</FOO>

<FOO> <BAR>文本</ BAR> </ FOO>

Before I'd look hard at the schema I had assumed that I could load them with an XmlNamespaceUpgradeReader. This is a derivation of XmlTextReader that does nothing but lie about the Namespace of every element. I'm using System.Xml on .NET 1.1.

在认真研究架构之前,我曾假设可以使用XmlNamespaceUpgradeReader加载它们。 这是XmlTextReader的派生,它仅对每个元素的名称空间起作用。 我在.NET 1.1上使用System.Xml。

public class XmlNamespaceUpgradeReader : XmlTextReader

公共类XmlNamespaceUpgradeReader:XmlTextReader

    {

{

        string oldNamespaceUri;

字符串oldNamespaceUri;

        string newNamespaceUri;

字符串newNamespaceUri;

        public XmlNamespaceUpgradeReader( TextReader reader, string oldNamespaceUri, string newNamespaceURI ):base( reader )

公共XmlNamespaceUpgradeReader(TextReader reader,字符串oldNamespaceUri,字符串newNamespaceURI):基本(reader)

        {

{

            this.oldNamespaceUri = oldNamespaceUri;

这个.oldNamespaceUri = oldNamespaceUri;

            this.newNamespaceUri = newNamespaceURI;

这个.newNamespaceUri = newNamespaceURI;

        }

}

        public override string NamespaceURI

公共重写字符串NamespaceURI

        {

{

            get

得到

            {

{

                // we are assuming XmlSchemaForm.Unqualified, therefore

//我们假设XmlSchemaForm.Unqualified,因此

                // we can't switch the NS here

//我们无法在此处切换NS

                if ( this.NodeType != XmlNodeType.Attribute &&

如果(此.NodeType!= XmlNodeType.Attribute &&

                    base.NamespaceURI == oldNamespaceUri )

base .NamespaceURI == oldNamespaceUri)

                {

{

                    return newNamespaceUri;

返回newNamespaceUri;

                }

}

                else

其他

                {

{

                    return base.NamespaceURI;

返回基础.NamespaceURI;

                }

}

            }

}

        }

}

    }

}

For example, if I did this:

例如,如果我这样做:

XmlTextReader reader = new XmlNamespaceUpgradeReader(    File.OpenText("MyLameDocument.xml"),     String.Empty,     "http://thenamespaceiwant"); 

XmlTextReader reader = new XmlNamespaceUpgradeReader(File.OpenText(“ MyLameDocument.xml”),String.Empty,“ http:// thenamespaceiwant ”);

XmlDocument doc = new XmlDocument();

XmlDocument doc =新的XmlDocument();

doc.Load(reader);

doc.Load(阅读器);

Console.WriteLine(doc.OuterXml);

Console.WriteLine(doc.OuterXml);

I would end up with this resulting XML:

我最终得到的结果是XML:

<FOO xmlns="http://thenamespaceiwant">
  <BAR xmlns="
http://thenamespaceiwant">text</BAR>
</FOO>

<FOO xmlns =“ http:// thenamespaceiwant ”> <BAR xmlns =“ http:// thenamespaceiwant” >文本</ BAR> </ FOO>

Seemed like this would validate. Well, not so much. The document, as you can see, is fine. It's exactly what you'd expect. But, the I remember/noticed that the document was elementFormDefault="unqualified" meaning that only the root node needs the namespace. So...

似乎这样可以验证。 好吧,不是很多。 如您所见,该文档很好。 正是您所期望的。 只是,我记得/注意到,该文件将elementFormDefault =“不合格”,这意味着只有根节点需要的命名空间。 所以...

public class XmlRootNamespaceUpgradeReader : XmlTextReader

公共类XmlNamespaceUpgradeReader:XmlTextReader

{

{

    string oldNamespaceUri;

字符串oldNamespaceUri;

    string newNamespaceUri;

字符串newNamespaceUri;

    public XmlRootNamespaceUpgradeReader( TextReader reader, string oldNamespaceUri, string newNamespaceURI ):base( reader )

公共XmlNamespaceUpgradeReader(TextReader reader,字符串oldNamespaceUri,字符串newNamespaceURI):基本(reader)

    {

{

        this.oldNamespaceUri = oldNamespaceUri;

这个.oldNamespaceUri = oldNamespaceUri;

        this.newNamespaceUri = newNamespaceURI;

这个.newNamespaceUri = newNamespaceURI;

    }

}

    public override string NamespaceURI

公共重写字符串NamespaceURI

    {

{

        get

得到

        {

{

            // we are assuming XmlSchemaForm.Unqualified, therefore

//我们假设XmlSchemaForm.Unqualified,因此

            // we can't switch the NS here

//我们无法在此处切换NS

            if ( Depth == 0 && this.NodeType != XmlNodeType.Attribute &&

if (深度== 0 &&此.NodeType!= XmlNodeType.Attribute &&

                    base.NamespaceURI == oldNamespaceUri )

base .NamespaceURI == oldNamespaceUri)

            {

{

                return newNamespaceUri;

返回newNamespaceUri;

            }

}

            else

其他

            {

{

            return base.NamespaceURI;

返回基础.NamespaceURI;

            }

}

        }

}

    }

}

    public override string Prefix

公共替代字符串前缀

    {

{

        get

得到

        {

{

            if(Depth == 0 && this.NodeType == XmlNodeType.Element)

if (深度== 0 &&此.NodeType == XmlNodeType.Element)

            {

{

                return "x";

返回“ x”;

            }

}

            return null;

返回null ;

        }

}

    }

}

}

}

...which results in a document like this:

...这将产生如下文档:

<x:FOO xmlns:x="http://thenamespaceiwant">
  <BAR
>text</BAR>
</x:FOO>

<x:FOO xmlns:x =“ http:// thenamespaceiwant ”> <BAR >文本</ BAR> </ x:FOO>

This document should now validate, and it fact it does in my test applications. When the document is loaded directly from a test file it works fine. When I run it directly through one of the extended "fake-out" XmlTextReaders, it doesn't work. It's as if my readers don't exist at all, even though their code does indeed execute.

该文档现在应该可以验证,并且事实证明它可以在我的测试应用程序中使用。 直接从测试文件加载文档时,它可以正常工作。 当我直接通过扩展的“伪装” XmlTextReaders之一运行它时,它不起作用。 好像我的读者根本不存在,即使他们的代码确实可以执行。

To be clear:

要清楚:

Original Doc -> XmlTextReader -> XmlValidatingReader -> doesn't validate (as expected)Original Doc -> XmlNamespaceUpgradingReader -> XmlValidatingReader -> doesn't validate (but it should!)Original Doc -> XmlNamespaceUpgradingReader -> XmlDocument -> write to file -> read from file -> XmlValidatingReader -> doesn't validate (as expected, it's "overqualified")Original Doc -> XmlRootNamespaceUpgradingReader -> XmlDocument -> write to file -> read from file -> XmlValidatingReader -> DOES VALIDATE (as expected)

原始文档-> XmlTextReader-> XmlValidatingReader->未验证(符合预期) 原始文档-> XmlNamespaceUpgradingReader-> XmlValidatingReader->无法验证(但应该验证!) 原始文档-> XmlNamespaceUpgradingReader-> XmlDocument->写入文件->从文件中读取-> XmlValidatingReader->无效(按预期,它是“合格”) 原始文档-> XmlRootNamespaceUpgradingReader-> XmlDocument->写入文件->从文件读取-> XmlValidatingReader->确认(如预期)

Why don't the "fake-out" XmlTextReaders work when chained together and feeding the XmlValidatingReader directly, but they do work when there's an intermediate format?

为什么将“伪装” XmlTextReaders链接在一起并直接送入XmlValidatingReader时不起作用,但是当存在中间格式时它们却起作用?

A few things about the XmlValidatingReader in .NET 1.1 (since it's obsolete in 2.0). While its constructor takes the abstract class XmlReader, internally it insists on an XmlTextReader. This is documented, but buried IMHO. Reflector shows us:

关于.NET 1.1中的XmlValidatingReader的一些注意事项(因为它在2.0中已作废)。 虽然其构造函数使用抽象类XmlReader,但在内部却坚持使用XmlTextReader。 这是有记录的,但掩埋恕我直言。 Reflector向我们展示:

XmlTextReader reader1 = reader as XmlTextReader;
if (reader1 == null)
{
    throw new ArgumentException(Res.GetString("Arg_ExpectingXmlTextReader"), "reader");
}

XmlTextReader reader1 =作为XmlTextReader的阅读器; 如果(reader1 == null) { 抛出新的ArgumentException(Res.GetString(“ Arg_ExpectingXmlTextReader”),“ reader”); }

<conjecture>When a class takes an abstract base class - the one it "should" - but really requires a specific derivation/implementation internally, it's a good hint that the OO hierarchy wasn't completely thought out and/or a refactoring that was going to happen in a future version never happened.</conjecture>

<conjecture>当一个类接受一个抽象的基类-它“应该”的一个基类-但实际上在内部需要特定的派生/实现时,这很好地暗示了OO层次结构没有被完全考虑和/或重构。将来的版本中不会发生。 </ conjecture>

Regardless, System.Xml in .NET 2.0 is much nicer and as well though-out as System.Xml 1.x was, 2.0 is considerably more thought out. However, I'm talking about 1.1.

不管怎样,.NET 2.0中的System.Xml都比System.Xml 1.x更好,尽管考虑得更深,但2.0的考虑要多得多。 但是,我说的是1.1。

<suspicion>I take this little design snafu as a strong hint that the XmlValidatingReader in .NET 1.1 has carnal knowledge of XmlTextReader and is probably making some assumptions about the underlying stream and doing some caching rather than taking my fake-out XmlReader's word for it.</suspicion> 

<怀疑>我以这个小小的设计技巧来强烈暗示.NET 1.1中的XmlValidatingReader具有XmlTextReader的基础知识,并且可能对底层流进行了一些假设并进行了一些缓存,而不是冒用我的假冒XmlReader的话。 。 </ suspicion>

If you're on, or were on, the System.Xml team let me know what the deal is and I'll update this post.

如果您正在使用System.Xml团队,请让我知道这是什么交易,我将更新此帖子。

I know that the XmlRootNamespaceUpgradingReader works because the XML is correct when it's written out to an intermediate. However, the InfoSet that the XmlValidatingReader acts on is somehow now the same.  How did we solve it? Since XmlValidatingReader needs an XmlTextReader that is more "legit," we'll give it one

我知道XmlRootNamespaceUpgradingReader可以工作,因为将XML写到中间件时它是正确的。 但是,XmlValidatingReader所作用的InfoSet现在某种程度上是相同的。 我们如何解决呢? 由于XmlValidatingReader需要一个更“合法”的XmlTextReader,因此我们给它一个

Original Doc -> XmlRootNamespaceUpgradingReader -> XmlDocument -> CloneXmlReader -> XmlValidatingReader -> DOES VALIDATE

原始文档-> XmlRootNamespaceUpgradingReader-> XmlDocument-> CloneXmlReader- > XmlValidatingReader->是否有效

This is cheesy, but if a better way is found at least it's compartmentalized and I can fix it in one place. We quickly run through the input XmlTextReader, write the Infoset out to a MemoryStream and return a "fresh" XmlTextReader and darn it if it doesn't work just fine.

这很俗气,但是如果找到更好的方法,至少它是分隔开的,我可以将它固定在一个地方。 我们快速遍历输入的XmlTextReader,将Infoset写出到MemoryStream,然后返回一个“新鲜的” XmlTextReader,如果它不能正常工作,则将其损坏。

/// <summary>

/// <摘要>

/// Makes an in memory complete, fresh COPY of an XmlReader. This is needed

///使XmlReader在内存中完成全新的COPY。 这是必需的

/// because the XmlValidatingReader takes only XmlTextReaders and isn't fooled

///因为XmlValidatingReader只接受XmlTextReaders并且不会被欺骗

/// by our XmlNamespaceUpgradingReader.

///由我们的XmlNamespaceUpgradingReader提供。

/// </summary>

/// </ summary>

/// <param name="reader"></param>

/// <param name =“ reader”> </ param>

/// <returns></returns>

/// <returns> </ returns>

protected XmlTextReader CloneReader(XmlTextReader reader)

受保护的XmlTextReader CloneReader(XmlTextReader reader)

{

{

    MemoryStream m = new MemoryStream();

MemoryStream m =新的MemoryStream();

    XmlTextWriter writer = new XmlTextWriter(m,Encoding.UTF8);

XmlTextWriter writer =新的XmlTextWriter(m,Encoding.UTF8);

    while (reader.Read())

而(reader.Read())

    {

{

        writer.WriteNode(reader,false);

writer.WriteNode(reader, false );

    }

}

    writer.Flush();

writer.Flush();

    m.Seek(0,SeekOrigin.Begin);

m.Seek(0,SeekOrigin.Begin);

    XmlTextReader returnedReader = new XmlTextReader(m);

XmlTextReader returnReader =新的XmlTextReader(m);

    return returnedReader;

返回returnReader;

}

}

Madness. Many thanks to Tomas Restrepo for his help and graciousness while debugging this issue!

疯狂。 非常感谢Tomas Restrepo在调试此问题时所提供的帮助和慷慨!

翻译自: https://www.hanselman.com/blog/xmlvalidatingreader-problems-over-derived-xmlreaders

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值