Как сделать второй тест пройденным в этих модульных тестах C # Xml? Что мне не хватает при инициализации XmlReaderSettings? - PullRequest
0 голосов
/ 18 февраля 2010

Описание проблемы:

  • Мне нужно исправить проблему с разрешением стандартных прав HTML.
  • Я реализовал HtmlEntityReader - реализацию XmlReader, в которой есть код для разрешения сущностей.
  • Публичный API нашей системы предоставляет методы с использованием XmlReader, поэтому пользователь может передать XmlReader, созданный с помощью одного из методов XmlReader.Create

Текущий код моих модульных тестов 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: Reference to undeclared entity 'nbsp'. Line 4, position 5.
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.Throw(String res, String arg, Int32 lineNo, Int32 linePos)
at System.Xml.XmlTextReaderImpl.HandleGeneralEntityReference(String name, Boolean isInAttributeValue, Boolean pushFakeEntityIfNullResolver, Int32 entityStartLinePos)
at System.Xml.XmlTextReaderImpl.HandleEntityReference(Boolean isInAttributeValue, EntityExpandType expandType, ref Int32 charRefEndPos)
at System.Xml.XmlTextReaderImpl.ParseText(ref Int32 startPos, ref Int32 endPos, ref Int32 outOrChars)
at System.Xml.XmlTextReaderImpl.ParseText()
at System.Xml.XmlTextReaderImpl.ParseElementContent()
at System.Xml.XmlTextReaderImpl.Read()
... private staff

Не могли бы вы дать быстрый совет илиСсылка на решение, пока я исправляю / исследую / ищу эту проблему своими силами?

Ответы [ 2 ]

1 голос
/ 21 февраля 2010

Я провел некоторое исследование по вашему вопросу, и, насколько я могу сказать, единственный способ убедиться, что символьные объекты разрешены, - это объявить их в DTD. Вы можете разрешить содержимое DTD самостоятельно (например, для кэширования), извлекая реализацию из базового класса Systm.Xml.XmlResolver и отвечая на вызовы GetEntity потоком, содержащим данные DTD.

Я некоторое время назад написал статью , в которой объясняется, как вставить DTD по умолчанию в XmlParserContext, если нет DTD, объявленного во входном документе. Эта статья немного устарела, но та же концепция продолжает работать с XmlReaderSettings & XmlReader.Create, используя перегрузку XmlReader.Create, которая принимает объект XmlParserContext в качестве аргумента.

Наконец, похоже, что .NET 4 немного нам поможет с новым производным XmlResolver с именем XmlPreloadedResolver , в котором, похоже, встроены DTD XHTML1 и RSS.

0 голосов
/ 27 сентября 2010

Самое смешное, что, как заметил сергейт, XmlTextReader не заботится о неопределенных сущностях при обработке фрагмента xml, а XmlReader -!

Таким образом, решением во многих случаях было бы попытаться использовать XmlTextRader.

...