Привет Я пытаюсь реализовать расширение для саксона в 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();
}
}
}
спасибо! :) Теперь он работает. –
Привет, Майкл. Я переключился с Saxon HE 9.5 на HE 9.7. Теперь мой код выходит из строя, потому что 'configuration.getProcessor()' теперь возвращает 'net.sf.saxon.s9api.Processor' вместо' Saxon.Api.Processor'. Я думаю, что интерфейс похож, но могу ли я как-то работать с классами из пространства имен Saxon.Api? Или мне нужно настроить код для использования в пространстве имен 'net.sf.saxon.s9api'? –
Если это так: как я могу преобразовать 'Saxon.Api.XdmNode' в' net.sf.saxon.s9api.XdmItem', который нужен метод 'net.sf.saxon.s9api.XPathCompiler.evaluate' как вход? И как я могу преобразовать результат метода 'evaluation' (' net.sf.saxon.s9api.XdmValue') обратно в 'Saxon.Api.XdmValue'? –