"Canonical Path" Function in XQuery? - xquery

Is there an standard XQuery function that will return a 'canonical' path for a node?
I mean something like:
/root/element/sub-element[0]

Since XQuery 3.0 there is fn:path($node), which does exactly that. If it is not supported by your query processor, you can also use FunctX's functx:path-to-node-with-pos($node), which unfortunately does not play well with namespaces.

Yes, in the predicate of a path expression using XQuery you can do something like:
doc("books.xml")/bookstore/book[substring(title,1,5)='Harry']
Hope that helps!

Related

XML XQuery basic querying results

I'm here with a question that I hope can be answered, which is really quite silly and basic.
I have a file of authors in the format of:
<authorRoot>
<author>
<info tags on author>
</author>
etc
</authorRoot>
and all I wish to do is, through FLWOR, return a list where each 'author' and its information is a different value, so when I run the query, the result should come out looking like
1. <author><info>.....</info></author>
2. <author><info>.....</info></author>
etc
and I am CERTAIN that something as simple as that should just be the following code
xquery version "1.0";
for $x in //author
return $x
yet when I do so, the query result comes out as
1.<author><info>...</info></author><author><info>...</info></author><author><info>...</info></author><author><info>...</info></author><author><info>...</info></author>....etc
I'm relatively new to XQuery, and I'm using AltovaSpy. I've done similar questions as basic as this (where I have a file of similar layout and I use essentially the same code, resulting in an xquery result page of multiple values, not just one long one) but for this file it just doesn't seem to work! Is it something with my code that I'm just not seeing? Or could it be the file, perhaps?
Thank you for whatever input you have on the situation.
Well, your reasoning is correct. .
It is just a formatting issue, it seems Altova prints the entire sequence in a single line without linebreaks.
You can also try it in my XQuery online tester, there you can see that the sequence is as you expected it to be.
If you watch this demo video of Altova XMLSpy and advance to 2:35 you will see how clicking on one of the toolbar buttons (which appears to be labeled "Pretty-print") will format the results of your XQuery as nicely indented XML.

XDMP Function: String to XML

Is there any method defined in marklogic function library, by which we can convert (or try to convert) a string (xs:string type) to an xml 'document' type? In my problem, I shall normally get an xml sent through request parameters. now I have to parse this xml as a document. So I have to take it as a string and parse it. What is the solution for this case?
I think xdmp:unquote is what you are looking for.
In XQuery 3.0 simply use the standard XPath 3.0 function parse-xml().
xdmp:eval("<ok/>")
or
xdmp:value("<ok/>")
Both of them can be use for your problem.
Regards

How can I find documents accessed to answer my Xquery query?

I have the following objective. I want to find, which documents contain my data when executing any kind of Xquery or XPath. In other words, I need every document that is providing me the result data for a given query. I try to do this in eXist-db environment, but I suppose there should be something on Xquery level.
I found op:context-document() operator which seems to have functionality I want, yet, as an operator it is not available for me. fn:document-uri also does not do the trick, as its $arg must be a document node, otherwise it returns an empty sequence.
Do you have any idea in mind? All the assistance is highly appreciated.
fn:base-uri() may help; it returns the base URI property of a node:
for $d in doc('....')/your[query]
return base-uri($d)
You can also use it to filter your documents for specific types:
collection('/path/to/documents')[ends-with(base-uri(), '.xml')]
Use the standard XPath / XQuery function collection() .
For example, using Saxon:
collection('file:///a/b/c/d?select=*.xml')[yourBooleanExpression]
selects the document nodes of all XML documents, residing in the /a/b/c/d directory of the filesystem, that satisfy your criteria (yourBooleanExpression evaluates to true())

Delete all documents matching a query?

I would like to delete all documents matching some predicates. The query I have come up with is as follows, but nothing is deleted from the database.
I suspect this is because the $doc is set to the XML value of the document rather than the document itself. Can anyone shed any light on this?
xquery version "1.0-ml";
for $doc in cts:search(fn:collection("MYCOLLECTIONNAME")/MyDocumentRoot,
cts:or-query((
cts:element-range-query (xs:QName("MyElement"), "=", "MyElementValue"),
)), "unfiltered" )
return xdmp:document-delete($doc);
The document looks like
<MyDocumentRoot>
<MyElementName>MyElementValue</MyElementName>
</MyDocumentRoot>
You are indeed passing the contents of the documents into xdmp:document-delete instead of its uri. You could derive the uri using for instance fn:base-uri(), but like this all docs you want to delete are retrieved from the database first, which is unnecessary.
Instead, enable the URI lexicon, and use cts:uris to do the deletion. It might also be wise to do the deletion in batches of lets say 1000 docs.
HTH!
xdmp:document-delete() takes the URI of the document, rather than a node. So the simplest fix would be to wrap $doc in base-uri(.):
return xdmp:document-delete(base-uri($doc))
But if you have the URI lexicon enabled, you can write a much faster query like this:
let $query := cts:and-query((
cts:collection-query("MYCOLLECTIONNAME"),
cts:or-query((...)) (: put your full or query here :)
))
for $uri in cts:uris("",(),$query) return xdmp:document-delete($uri)
In the latter case, you avoid having to read each document to get its URI.
xdmp:collection-delete("MYCOLLECTIONNAME") is also worth a mention.
On the last line, change to
xdmp:document-delete(fn:base-uri($doc));

Pattern matching using decorators

I want to define a specific URL pattern using Sitemesh decorators.xml. I want to define a decorator that matches all URLs ending with "/story/_NUMBER_" to be targetted by the decorator. I tried:
<decorator name="customMain" page="customMain.jsp">
<pattern>/story/[0-9]+</pattern>
</decorator>
But this does not work.. Do regular expressions work in decorators.xml? If not, how do I target URLs that end with the above pattern?
Just ran into this myself. I don't think it's possible to use regular expressions at all. Only wildcard patterns with * and ?.
Look at the source here for more details.

Resources