0

问题描述:

  • 我需要解决解决标准 HTML 实体的问题。
  • 我已经实现了 HtmlEntityReader - XmlReader 的实现,它有一个解析实体的代码
  • 我们系统的公共 API 提供了一个使用 XmlReader 的方法,因此用户可以传递使用 XmlReader.Create 方法之一创建的 XmlReader

我的 xml 单元测试的当前代码如下:

using System.Xml;
using NUnit.Framework;

namespace Tests
{
    [TestFixture]
    public class XmlTests
    {
        // this test works
        [Test]
        public void TestEntitiesResolving1()
        {
            var path = QA.ResolvePath(@"html\bugs\317.html");
            using (var reader = new XmlTextReader(path, new NameTable()))
            {
                reader.XmlResolver = null; //to prevent DTD downloading
                var wrapper = new HtmlEntityReader(reader, XmlUtils.HtmlEntities);
                while (wrapper.Read()) { }
            }
        }

        // this test does not work - why?
        // what's the difference in initialization of internal XmlTextReaderImpl?
        [Test]
        public void TestEntitiesResolving2()
        {
            var path = QA.ResolvePath(@"html\bugs\317.html");
            var settings = new XmlReaderSettings
                           {
                               XmlResolver = null, //to prevent DTD downloading
                               NameTable = new NameTable(),
                               ProhibitDtd = false,
                               CheckCharacters = false,
                           };
            using (var reader = XmlReader.Create(path, settings))
            {
                var wrapper = new HtmlEntityReader(reader, XmlUtils.HtmlEntities);
                while (wrapper.Read()) { }
            }
        }
    }
}

HtmlEntityReader 的部分代码如下:

internal sealed class HtmlEntityReader : XmlReader
{
    readonly XmlReader _impl;
    readonly Hashtable _entitySet;
    string _entityValue;

    public HtmlEntityReader(XmlReader reader, Hashtable entitySet)
    {
        if (reader == null) throw new ArgumentNullException("reader");
        if (entitySet == null) throw new ArgumentNullException("entitySet");
        _impl = reader;
        _entitySet = entitySet;
    }

    public override XmlNodeType NodeType
    {
        get { return _entityValue != null ? XmlNodeType.Text : _impl.NodeType; }
    }

    public override string LocalName
    {
        get { return _entityValue != null ? string.Empty : _impl.LocalName; }
    }

    public override string Prefix
    {
        get { return _entityValue != null ? string.Empty : _impl.Prefix; }
    }

    public override string Name
    {
        get { return _entityValue != null ? string.Empty : _impl.Name; }
    }

    public override bool HasValue
    {
        get { return _entityValue != null || _impl.HasValue; }
    }

    public override string Value
    {
        get { return _entityValue ?? _impl.Value; }
    }

    public override bool CanResolveEntity
    {
        get { return true; }
    }

    public override void ResolveEntity()
    {
        //it seems this does not call - why?
    }

    public override bool Read()
    {
        _entityValue = null;
        if (!_impl.Read()) return false;
        if (NodeType == XmlNodeType.EntityReference)
        {
           //resolving of entity reference
           _entityValue = (string)_entitySet[Name];
        }
        return true;
    }

    // ... delegation of XmlReader abstract methods to _impl
}

我有一个例外:

System.Xml.XmlException:对未声明实体“nbsp”的引用。第 4 行,第 5 位。
在 System.Xml.XmlTextReaderImpl.Throw(异常 e)
在 System.Xml.XmlTextReaderImpl.Throw(字符串 res,字符串 arg,Int32 lineNo,Int32 linePos)
在 System.Xml.XmlTextReaderImpl.HandleGeneralEntityReference(字符串名称,布尔 isInAttributeValue,布尔 pushFakeEntityIfNullResolver,Int32 entityStartLinePos)
在 System.Xml.XmlTextReaderImpl.HandleEntityReference(布尔 isInAttributeValue,EntityExpandType expandType,ref Int32 charRefEndPos)
在 System.Xml.XmlTextReaderImpl.ParseText(参考 Int32 startPos,参考 Int32 endPos,参考 Int32 outOrChars)
在 System.Xml.XmlTextReaderImpl.ParseText()
在 System.Xml.XmlTextReaderImpl.ParseElementContent()
在 System.Xml.XmlTextReaderImpl.Read()
...私人员工

在我通过自己的努力修复/调查/搜索此问题时,您能否提供快速建议或解决方案链接?

4

2 回答 2

1

我已经对您的问题进行了一些研究,并且尽我所能告诉确保角色实体得到解决的唯一方法是在 DTD 中声明它们。通过从Systm.Xml.XmlResolver基类派生实现并使用包含 DTD 数据的流响应 GetEntity 调用,您可以自己解析 DTD 内容(例如,用于缓存) 。

前段时间我写了一篇文章,解释了如果输入文档中没有声明 DTD,如何将默认 DTD 推送到 XmlParserContext 上。这篇文章有点过时了,但同样的概念仍然适用于 XmlReaderSettings 和 XmlReader.Create,方法是使用接受XmlParserContext对象作为参数的 XmlReader.Create 重载。

最后,看起来 .NET 4 将通过一个名为XmlPreloadedResolver的新 XmlResolver 衍生工具帮助我们,它似乎内置了 XHTML1 和 RSS DTD。

于 2010-02-21T09:14:35.613 回答
0

有趣的是,正如 sergeyt 所说,在处理 xml 片段时,XmlTextReader 不关心未定义的实体,而 XmlReader 则关心!

因此,在许多情况下,一个解决方案是尝试使用 XmlTextRader。

于 2010-09-27T09:21:37.673 回答