13 марта 2018 г.

XPathNavigator ошибка при парсе.


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

Работая с XPathNavigator, XPathDocument (возможно и с XDocument) и используя свой класс XsltContext (подкласс XmlNamespaceManager) контекст, что бы писать свои функции для XPath, можно словить исключение:
System.NullReferenceException "Object reference not set to an instance of an object."
   at MS.Internal.Xml.XPath.BaseAxisQuery.matches(XPathNavigator e)
   at MS.Internal.Xml.XPath.CacheChildrenQuery.Advance()
   at MS.Internal.Xml.XPath.AttributeQuery.Advance()
   at MS.Internal.Xml.XPath.LogicalExpr.cmpQueryQueryE(Op op, Object val1, Object val2)
   at MS.Internal.Xml.XPath.LogicalExpr.Evaluate(XPathNodeIterator nodeIterator)
   at MS.Internal.Xml.XPath.FilterQuery.EvaluatePredicate()
   at MS.Internal.Xml.XPath.FilterQuery.Advance()
   at MS.Internal.Xml.XPath.CacheChildrenQuery.GetNextInput()
   at MS.Internal.Xml.XPath.CacheChildrenQuery.Advance()
   at MS.Internal.Xml.XPath.CacheChildrenQuery.GetNextInput()
   at MS.Internal.Xml.XPath.CacheChildrenQuery.Advance()
   at MS.Internal.Xml.XPath.XPathSelectionIterator.MoveNext()
Причина: 
При использовании своей реализации XsltContext пропадает проверка на наличие добавленного namespace (через AddNamespace) у контекст менеджера. В результате, казалось бы обычный XPath запрос перестаёт ругаться на неизвестное пространство имен исключениями формата "XPathException. Additional information: Namespace prefix 'myns1' is not defined." и просто сваливается с NullReferenceException без какой либо причины.

Решение:
Добавить в XmlNamespaceManager namespace из XPath запроса.

Демонстрация:

Для наглядности приведу код, который будет падать с этой ошибкой. Если в нем раскомментировать "// Error fix" строку, тогда ошибка пропадёт.

static void Main(string[] args)
{
    var xml = @"<?xml version=""1.0"" encoding=""utf-8""?>
    <root xmlns:myns1=""http://mynamespace1.com/format#"">
        <MyText>Text1</MyText>
        <myns1:MyNamespace>Value1</myns1:MyNamespace>
    </root>";
 
    // Загружаем XML
    var document = new XPathDocument(new StringReader(xml));
 
    // Создаем навигатор для работы
    var navigator = document.CreateNavigator().SelectSingleNode("//MyText");
 
    // Используем свой контекст менеджер
    var manager = new XmlNamespaceManager(new NameTable());
 
    // Error fix (раскомментить)
    //manager.AddNamespace("myns1", "http://mynamespace1.com/format#");
 
    // Запрос
    var allNodes = navigator.Select("//*[myns1:MyNamespace/text() = 'Value1']", manager);
            
    // Exception here
    if (allNodes.MoveNext())
    {
                
    }
}
 
private class TestXsltContext : XsltContext
{
    public TestXsltContext(NameTable table) : base(table) { }
 
    public override IXsltContextVariable ResolveVariable(string prefix, string name) {
        throw new NotImplementedException();
    }
 
    public override IXsltContextFunction ResolveFunction(string prefix, string name, XPathResultType[] ArgTypes) {
        throw new NotImplementedException();
    }
 
    public override bool PreserveWhitespace(XPathNavigator node) {
        throw new NotImplementedException();
    }
 
    public override int CompareDocument(string baseUri, string nextbaseUri) {
        throw new NotImplementedException();
    }
 
    public override bool Whitespace { get; }
}

.

Комментариев нет:

Отправить комментарий