问题描述
在C#程序(.NET Framework 4.8)中,我在运行时创建了XDocument
。我需要针对此XML树在运行时执行几个XQuery评估。各个查询来自外部资源,因此在设计时我不知道它们的详细信息。查询可能包含诸如exists()
,not()
,empty()
之类的函数或诸如every $x in ... satiesfies ...
或generate-id()
之类的东西。
第一步,我真正需要知道的是查询是否产生结果(即从XDocument
返回的某物不为空)。
最初,我只是尝试使用XElement.XPathEvaluate(query)
,只要所说的查询实际上只是一个XPath评估,它就可以正常工作-但如果它包含诸如exists(...)
之类的函数,则会引发错误。告诉我我需要XsltContext。我所拥有的是:
public bool XPathExists(string context,string xpath)
{
Object result;
try
{
XElement contextElement = xmlTree.Root.XPathSelectElement(context,namespaces);
result = contextElement.XPathEvaluate(xpath,namespaces);
}
catch (Exception e) // xpath can't be evaluated
{
Debug.Print(e.Message);
return false;
}
return (result != null);
}
所以我认为我需要使用 Saxon-HE 来执行查询,因为它完全支持XQuery。不幸的是,我很难用内存中的XDocument作为源来正确初始化Saxon的XQueryEvaluator(或者完全使用它)。另外,我在哪里/如何向Saxon提供要在其中评估xquery的初始上下文节点方面毫无头绪。既没有阅读the API documentation,也没有读迈克尔·凯(Michael Kay)的书“ XSLT 2.0和XPath 2.0”中关于将Saxon与.NET结合使用的一章,也没有普遍地搜索互联网(特别是StackOverflow)都没有使我着迷。
到目前为止,我仍然坚持使用(当然不起作用)“代码”:
public bool XQueryYieldsResults(XDocument xmlTree,string contextNode,string xqueryExpression)
{
var processor = new Processor();
XdmNode input = processor.NewDocumentBuilder().Build(xmlTree);
var compiler = processor.NewXQueryCompiler();
var exececutable = compiler.Compile(xqueryExpression); // how to set context?
var xqueryEvaluator = exececutable.Load(); // ...?!
// ...
// var result = *the xquery's result*;
// ...
return (result != null);
}
对不起,我真的不知道从哪里开始!任何有关在这里做什么的提示-或更具体地说:如何在使用Saxon-HE的XDocument的给定上下文中执行XQuery -非常感谢! :-)
解决方法
XDocument和Saxon的DocumentBuilder之间唯一合适的接口是const handleUserChange = useCallback((user) => {
setCurrentUser(user);
setPending(false);
},[]);
useEffect(() => {
if (pending) {
AccountHandler.getInstance().registerAuthStateChangeObserver(handleUserChange)
};
return () => {
// here you need to unsubscribe
AccountHandler.getInstance().unregisterAuthStateChangeObserver(handleUserChange);
}
},[])
方法,该方法采用Build
:https://www.saxonica.com/html/documentation/dotnetdoc/Saxon/Api/DocumentBuilder.html#Build(XmlReader)。
因此XmlReader
应该可以运行XPath 3.1或XQuery 3.1。但是,您将无法将结果追溯到XDocument中的节点。
XdmNode input = processor.NewDocumentBuilder().Build(xmlTree.CreateReader())
另一方面,您的大多数带有var processor = new Processor();
XdmNode input = processor.NewDocumentBuilder().Build(xmlTree.CreateReader());
var compiler = processor.NewXQueryCompiler();
var exececutable = compiler.Compile(xqueryExpression);
var xqueryEvaluator = exececutable.Load();
xqueryEvaluator.ContextItem = input;
XdmItem result = xqueryEvaluator.EvaluateSingle();
return (result != null);
,not
,empty
的示例将始终返回布尔值,而不是null。
我不太了解every ..
作为字符串在您的方法中具有什么值。因此,上面的代码应该针对完整的文档运行任何XQuery。
如果您只想运行带有检查布尔值的表达式的XQuery或XPath,那么这里是一个示例:
contextNode
与 string[] examples = { "exists(//foo)","not(//bar)","empty(//bar)",@"every $x in //item satisfies matches($x/foo,'^\p{L}+$')" };
XDocument doc = XDocument.Parse(@"<root>
<items>
<item>
<foo>a</foo>
</item>
<item>
<foo>b</foo>
</item>
</items>
</root>");
Processor processor = new Processor();
XPathCompiler xpathCompiler = processor.NewXPathCompiler();
DocumentBuilder docBuilder = processor.NewDocumentBuilder();
XdmNode xdmDoc = docBuilder.Build(doc.CreateReader());
foreach (string expression in examples)
{
Console.WriteLine("{0} evaluates to {1}.",expression,xpathCompiler.EvaluateSingle(expression,xdmDoc));
}
和XQueryCompiler
的相同之处如下:
XQueryEvaluator
,
从您的XDocument xmlTree并提供Martin提供的链接。
string xml = xmlTree.ToString();
StringReader sReader = new StringReader(xml);
XmlReader xReader = XmlReader.Create(sReader);
XdmNode node = Build(reader);