0

問題の説明:

  • 標準のHTMLエンティティの解決に関する問題を修正する必要があります。
  • 私はHtmlEntityReaderを実装しました-エンティティを解決するためのコードを持つXmlReaderの実装
  • システムのパブリックAPIは、XmlReaderを使用するメソッドを提供するため、ユーザーはXmlReader.Createメソッドの1つを使用して作成された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(Exception e)で
System.Xml.XmlTextReaderImpl.Throw(String res、String arg、Int32 lineNo、Int32 linePos)で
System.Xml.XmlTextReaderImpl.HandleGeneralEntityReference(String name、Boolean isInAttributeValue、Boolean pushFakeEntityIfNullResolver、Int32 entityStartLinePos)で
System.Xml.XmlTextReaderImpl.HandleEntityReference(Boolean isInAttributeValue、EntityExpandType ExpandType、ref Int32 charRefEndPos)で
System.Xml.XmlTextReaderImpl.ParseText(ref Int32 startPos、ref Int32 endPos、ref 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 にプッシュする方法を説明する記事を書きました。この記事は少し古くなっていますが、 XmlParserContextオブジェクトを引数として受け入れる XmlReader.Create オーバーロードを使用することで、同じ概念が XmlReaderSettings と XmlReader.Create で引き続き機能します。

最後に、.NET 4 は、XHTML1 と RSS DTD が組み込まれているように見えるXmlPreloadedResolverという名前の新しい XmlResolver 派生物で、私たちを少し助けてくれるようです。

于 2010-02-21T09:14:35.613 に答える
0

面白いことに、sergeyt が指摘したように、XmlTextReader は xml フラグメントを処理するときに未定義のエンティティを気にしませんが、XmlReader は気にします!

したがって、多くの場合、解決策は XmlTextRader を試すことです。

于 2010-09-27T09:21:37.673 に答える