2017-02-10 6 views
1

Привет Я пытаюсь реализовать расширение для саксона в C#. Я использую интерфейс saxon9he. Сам расширение отлично работает, но теперь я хочу использовать выражения XPath для получения значений из узла. Я разбиваю его на соответствующую часть кода (остальное работает нормально).Saxon extension: XPath on XdmNode

Расширение имеет два аргумента. Первый - это строка, вторая - набор узлов.

public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context) 
{ 
    if (arguments.Length == 2) 
    { 
     arguments[0].MoveNext(); 

     string text = (arguments[0].Current as XdmAtomicValue).Value as string; 
     IXdmEnumerator enumerator = arguments[1]; 

     while (enumerator.MoveNext()) 
     { 
      XdmNode node = (XdmNode)enumerator.Current; 

      // how can I get values from node here by using XPath expressions? 
      // e.g. I want the value of the attribute "type" of the subnode "xy" 
      // XPath would be something like this: "./xy/@type" 

      text = text.Replace(node.NodeName.LocalName, node.StringValue); 
     } 

     var result = new XdmAtomicValue(text); 

     return (IXdmEnumerator)result.GetEnumerator(); 
    } 
    ... 
} 

3 комментария в середине показывают мою проблему. Я хочу получить доступ к подносам, атрибутам и т. Д. Выражениям XPath. Это упрощенная версия. XPath следует передать в качестве дополнительного аргумента позже. Таким образом, это не фиксированное выражение XPath, которое я мог бы преобразовать в код. Мне действительно нужен оценщик XPath.

Я увидел решение, создав XPathEvaluator с процессора. Но на данный момент у меня нет процессора, или я?

Спасибо за помощь.

Вот решение (спасибо Майклу):

var configuration = context.Implementation.getConfiguration(); 
var processor = (Processor)configuration.getProcessor(); 
var xpathCompiler = processor.NewXPathCompiler(); 

while (enumerator.MoveNext()) 
{ 
    XdmNode node = (XdmNode)enumerator.Current; 

    var keyResult = xpathCompiler.Evaluate(searchXPath, node); 
    var valueResult = xpathCompiler.Evaluate(replaceXPath, node); 

    string key = ""; 
    string value = ""; 

    if (keyResult is XdmAtomicValue) 
     key = (string)(keyResult as XdmAtomicValue).Value; 
    else if (keyResult is XdmNode) 
     key = (string)(keyResult as XdmNode).StringValue; 

    if (valueResult is XdmAtomicValue) 
     value = (string)(valueResult as XdmAtomicValue).Value; 
    else if (valueResult is XdmNode) 
     value = (string)(valueResult as XdmNode).StringValue; 

    if (string.IsNullOrWhiteSpace(key) || value == null) 
     continue; 

    text = text.Replace(key, value); 
} 

Раствор для Saxon 9.7:

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

public static void RegisterSaxonExtensions(Saxon.Api.Processor processor) 
{ 
    processor.RegisterExtensionFunction(new MyExtension1(processor)); 
    processor.RegisterExtensionFunction(new MyExtension2(processor)); 
} 

... 

public class MyExtension1 : Saxon.Api.ExtensionFunctionDefinition 
{ 
    private Saxon.Api.Processor processor = null; 

    public MyExtension1(Saxon.Api.Processor processor) 
    { 
     this.processor = processor; 
    } 

    public override ExtensionFunctionCall MakeFunctionCall() 
    { 
     return new MyExtension1Call(this.processor); 
    } 

    ... 
} 

public class MyExtension1Call : Saxon.Api.ExtensionFunctionCall 
{ 
    private Saxon.Api.Processor processor = null; 

    public MyExtension1Call(Saxon.Api.Processor processor) 
    { 
     this.processor = processor; 
    } 

    public override IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context) 
    { 
     if (arguments.Length == 2) 
     { 
      arguments[0].MoveNext(); 

      string text = (arguments[0].Current as XdmAtomicValue).Value as string; 
      IXdmEnumerator enumerator = arguments[1]; 
      var xpathCompiler = this.processor.NewXPathCompiler(); 

      while (enumerator.MoveNext()) 
      { 
       XdmNode node = (XdmNode)enumerator.Current; 

       var keyResult = xpathCompiler.Evaluate(searchXPath, node); 
       var valueResult = xpathCompiler.Evaluate(replaceXPath, node); 

       string key = ""; 
       string value = ""; 

       if (keyResult is XdmAtomicValue) 
        key = (string)(keyResult as XdmAtomicValue).Value; 
       else if (keyResult is XdmNode) 
        key = (string)(keyResult as XdmNode).StringValue; 

       if (valueResult is XdmAtomicValue) 
        value = (string)(valueResult as XdmAtomicValue).Value; 
       else if (valueResult is XdmNode) 
        value = (string)(valueResult as XdmNode).StringValue; 

       if (string.IsNullOrWhiteSpace(key) || value == null) 
        continue; 

       text = text.Replace(key, value); 
      } 

      var result = new XdmAtomicValue(text); 

      return (IXdmEnumerator)result.GetEnumerator(); 
     } 
    } 
} 

ответ

0

DynamicContext.Implementation дает объект XPathContext, это имеет метод getConfiguration(), чтобы добраться до конфигурации, и объект Процессор должен быть найден в Configuration.getProcessor(). Из этого вы сможете создать XPathEvaluator.

+0

спасибо! :) Теперь он работает. –

+0

Привет, Майкл. Я переключился с Saxon HE 9.5 на HE 9.7. Теперь мой код выходит из строя, потому что 'configuration.getProcessor()' теперь возвращает 'net.sf.saxon.s9api.Processor' вместо' Saxon.Api.Processor'. Я думаю, что интерфейс похож, но могу ли я как-то работать с классами из пространства имен Saxon.Api? Или мне нужно настроить код для использования в пространстве имен 'net.sf.saxon.s9api'? –

+0

Если это так: как я могу преобразовать 'Saxon.Api.XdmNode' в' net.sf.saxon.s9api.XdmItem', который нужен метод 'net.sf.saxon.s9api.XPathCompiler.evaluate' как вход? И как я могу преобразовать результат метода 'evaluation' (' net.sf.saxon.s9api.XdmValue') обратно в 'Saxon.Api.XdmValue'? –

Смежные вопросы