Hi I try to implement an extension for saxon in C#. I use the saxon9he interface. The extension itself works fine but now I want to use XPath expressions to get values from a node. I break it down to the relevant code part (the rest is working fine).
The extension has two arguments. The first one is a string, the second one is a node-set.
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();
}
...
}
The 3 comments in the middle show my problem. I want to access subnodes, attributes and so on by XPath expressions. This is a simplified version. The XPath should be passed as an additional argument later. So it is not a fixed XPath expression that I could transform to code. I really need an XPath evaluator.
I saw a solution by creating an XPathEvaluator from a Processor. But I have no Processor at this point, or do I?
Thanks for help.
Here is the solution (thanks to Michael):
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);
}
Solution for Saxon 9.7:
The solution above doesn't work for Saxon 9.7 anymore. In this case I pass the processor to the extension classes and from there to the extension call classes at the time I register the extensions.
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();
}
}
}