I'm using OSM 7.2.0.3 and I have cartridge with an Order Recognition Rule, with its Order Data Rule (inside Transformation tab)
In the ODR I have this XQuery code:
declare namespace im="http://xxx";
declare namespace xs="http://www.w3.org/2001/XMLSchema";
declare variable $order := fn:root(.)/im:Order;
<_root>
<Order>
{
for $moli in $order/MainOrderLineItem
return {
<OrderLineItem>
{$moli/LineItemAttributeInfo/LineItemAttribute}
</OrderLineItem>
{
for $oli in $moli/OrderLineItem
return
<OrderLineItem>
{$oli/LineItemAttributeInfo/LineItemAttribute}
</OrderLineItem>
}
}
}
</Order>
</_root>
There's no compile error in OSM, but on runtime I get:
Invalid Order Specification Fault
Order data expression failed due to oracle.communications.ordermanagement.rule.XMLRuleException
I run the OSM by submitting an XML through Web Service.
Thanks a lot for your replies.
The returned XML should actually be in parentheses instead of braces. There also needs to be a comma between the first returned OrderLineItem element and the FLWOR expression instead of wrapping it in braces:
declare namespace im="http://xxx";
declare namespace xs="http://www.w3.org/2001/XMLSchema";
declare variable $order := fn:root(.)/im:Order;
<_root>
<Order>{
for $moli in $order/MainOrderLineItem
return (
<OrderLineItem>
{$moli/LineItemAttributeInfo/LineItemAttribute}
</OrderLineItem>,
for $oli in $moli/OrderLineItem
return
<OrderLineItem>
{$oli/LineItemAttributeInfo/LineItemAttribute}
</OrderLineItem>
)
}</Order>
</_root>
Related
Will elaborate - when I execute the following command :
let $value := xdmp:forest-status(
xdmp:forest-open-replica(
xdmp:database-forests(xdmp:database("Documents"))))
return $value
Above query returns a lot of information about the database "Documents" forest, like - forest-id, host-id, etc.
I only require that it should return only the "state" of my forest. How do I do that?
Use XPath to select what you want to return.
let $value := xdmp:forest-status(
xdmp:forest-open-replica(
xdmp:database-forests(xdmp:database("Documents"))))
return $value/*:state/text()
Also, no need for a FLWOR you could make it a one-liner:
xdmp:forest-status(
xdmp:forest-open-replica(
xdmp:database-forests(xdmp:database("Documents"))))/*:state/text()
Or you may find that using the arrow operator makes things easier to read instead of nested function calls and tons of parenthesis wrapping them:
(xdmp:database("Documents")
=> xdmp:database-forests()
=> xdmp:forest-open-replica()
=> xdmp:forest-status()
)/*:state/text()
The XML elements in the response are in the http://marklogic.com/xdmp/status/forest namespace. So, you would either need to declare the namespace (i.e. declare namespace f = "http://marklogic.com/xdmp/status/forest";) and use the prefix in your XPath (i.e. f:state), or just use the wildcard as I have done *:state
How to call a custom xquery function in exist-db using the REST API ?
Is it possible to have more than 1 function in the xquery file ?
declare function local:toto() as node() {
return doc("/db/ProjetXML/alice.xml")/raweb/identification/projectName)
};
declare function local:pomme() as node() {
return doc("/db/ProjetXML/carmen.xml")/raweb/identification/projectSize);
};
If I call it using :
http://localhost:8080/exist/rest/db/ProjetXML/orange.xqy?_query=local:toto()
I get the following error :
err:XPST0017 Call to undeclared function: local:toto [at line 1, column 1, source: local:toto()]
Your help is appreciated.
You have syntax errors in your XQuery:
You have two functions named local:toto(). Each function must have a distinct name.
There is no semicolon following the function definition, i.e. } should be };.
Also you should remove the return expression, as there is no preceding binding.
Another option would be to parameterize the input file, e.g.:
import module namespace request="http://exist-db.org/xquery/request";
declare function local:toto($name as xs:string) as node() {
let $doc :=
if($name eq "carmen")then
doc("/db/ProjetXML/carmen.xml")
else
doc("/db/ProjetXML/alice.xml")
return
$doc/raweb/identification/projectName);
};
local:toto(request:get-parameter("name", "alice"))
You can then call this via the REST Server using a URL like:
http://localhost:8080/exist/rest/db/ProjetXML/orange.xqy?name=carmen
I need to use a counter to remember how many node I have dealed with. So I defined a global var $classCounter. For some unknown reasons, I get an error from zorba:
test.xqy>:15,9: error [zerr:XSST0004]: "local:owlClassNameBuilerHelper": function declared nonsequential but has sequential body
I really don't understand what this error means. How to implement a global counter in XQuery?
The whole xqy file is:
declare namespace rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
declare namespace owl="http://www.w3.org/2002/07/owl#";
declare namespace xsd="http://www.w3.org/2001/XMLSchema#";
declare namespace rdfs="http://www.w3.org/2000/01/rdf-schema#";
import module namespace functx="http://www.functx.com";
declare variable $srcDoc:="test_xsd.xml"; (:need to adjust the input XSD file here:)
declare variable $defaultXMLNS:="http://www.test.com#";
declare variable $defaultXMLBase:=$defaultXMLNS;
declare variable $classCounter:=0;
declare function local:owlClassNameBuilerHelper($pnode as node()*)
as xs:string?
{
$classCounter:=classCounter+1;
let $tmp:=""
return
(
"haha"
(:if(functx:if-empty($pnode/#name, "-1")!="-1") (:if the name attr doesn't exist:)
then data($pnode/ancestor::element[1]/#name) (:get the name attr of first ancestor named element:)
else data($pnode/#name):)
)
};
element rdf:RDF
{
namespace {""} {$defaultXMLNS},
namespace {"owl"} {"http://www.w3.org/2002/07/owl#"},
namespace {"xsd"} {"http://www.w3.org/2001/XMLSchema#"},
namespace {"rdfs"} {"http://www.w3.org/2000/01/rdf-schema#"},
attribute xml:base {$defaultXMLBase}
}
command line:
zorba -i -f -q test.xqy
I need to use a counter to remember how many node I have dealed with.
Firstly, XQuery is a functional programming language. That's a completely different processing model: you can't "remember" what you have "dealt with", because there is no memory and no time dimension. Functions are mathematical functions, they can't have side-effects like updating global variables.
Now, the error message suggests to me that the particular XQuery processor you are using (Zorba) has extensions that allow you to depart from the pure functional programming model; but you are using the extensions incorrectly. In particular, if you want a function to have side-effects then you must declare the function as such. You'll have to look in the Zorba documentation for how to do that, because there is no standard.
I have a content which is neither a valid HTML nor a XML in my legacy database. Considering the fact, it would be difficult to clean the legacy, I want to tidy this up in MarkLogic using xdmp:tidy. I am currently using ML-8.
<sub>
<p>
<???†?>
</p>
</sub>
I'm passing this content to tidy functionality in a way :
declare variable $xml as node() :=
<content>
<![CDATA[<p><???†?></p>]]>
</content>;
xdmp:tidy(xdmp:quote($xml//text()),
<options xmlns="xdmp:tidy">
<assume-xml-procins>yes</assume-xml-procins>
<quiet>yes</quiet>
<tidy-mark>no</tidy-mark>
<enclose-text>yes</enclose-text>
<indent>yes</indent>
</options>)
As a result it returns :
<p>
<? ?†?>
</p>
Now this result is not the valid xml format (I checked it via XML validator) due to which when I try to insert this XML into the MarkLogic it throws an error saying 'MALFORMED BODY | Invalid Processing Instruction names'.
I did some investigation around PIs but not much luck. I could have tried saving the content without PI but this is also not a valid PI too.
That is because what you think is a PI is in fact not a PI.
From W3C:
2.6 Processing Instructions
[Definition: Processing instructions (PIs) allow documents to contain
instructions for applications.]
Processing Instructions
[16] PI ::= '' Char*)))?
'?>'
[17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' |
'l'))
So the PI name cannot start with ? as in your sample ??†
You probably want to clean up the content before you pass it to tidy.
Like below:
declare variable $xml as node() :=
<content><![CDATA[<p>Hello <???†?>world</p>]]></content>;
declare function local:copy($input as item()*) as item()* {
for $node in $input
return
typeswitch($node)
case text()
return fn:replace($node,"<\?[^>]+\?>","")
case element()
return
element {name($node)} {
(: output each attribute in this element :)
for $att in $node/#*
return
attribute {name($att)} {$att}
,
(: output all the sub-elements of this element recursively :)
for $child in $node
return local:copy($child/node())
}
(: otherwise pass it through. Used for text(), comments, and PIs :)
default return $node
};
xdmp:tidy(local:copy($xml),
<options xmlns="xdmp:tidy">
<assume-xml-procins>no</assume-xml-procins>
<quiet>yes</quiet>
<tidy-mark>no</tidy-mark>
<enclose-text>yes</enclose-text>
<indent>yes</indent>
</options>)
This would do the trick to get rid of all PIs (real and fake PIs)
Regards,
Peter
I have a content.xml modelled as below
<root>
<childnode>
Some text here
</childnode>
</root>
I am trying to remove the <childnode> and update the content.xml with only the value of it
so the output looks like
<root>
Some Text here
</root>
I wrote a function to perform this but anytime I run it it gives me error as "unexpected token: modify". I was thinking of a way to accomplish this without using functx functions.
xquery version "1.0";
declare namespace request="http://exist-db.org/xquery/request";
declare namespace file="http://exist-db.org/xquery/file";
declare namespace system="http://exist-db.org/xquery/system";
declare namespace util="http://exist-db.org/xquery/util";
declare namespace response="http://exist-db.org/xquery/response";
declare function local:contentUpdate() {
let $root := collection('/lib/repository/content')//root/childNode
let $rmChild := for $child in $root
modify
(
return rename node $child as ''
)
};
local:updateTitle()
Thanks in advance
There are multiple problems with your query:
Updating functions must be declared as updating.
You're calling another function than you defined (probably you didn't notice as there still have been syntax errors).
Rename node expects some element (or processing instruction, attribute) as target, the empty string is not allowed.
At least BaseX doesn't allow updating statements when defining code as XQuery 1.0. Maybe exist doesn't care about this, try adding it if you need to know.
You do not want to rename, but replace all <childnode />s with its contents, use replace node.
This code fixes all these problems:
declare updating function local:contentUpdate() {
let $root := collection('/lib/repository/content')
return
for $i in $root//childnode
return
replace node $i with $i/data()
};
local:contentUpdate()
eXist-db's XQuery Update syntax is documented at http://exist-db.org/exist/update_ext.xml. Note that this syntax predates the release of the XQuery Update Facility 1.0, so the syntax is different and remains unique to eXist-db.
The way to do what you want in eXist-db is as follows:
xquery version "1.0";
declare function local:contentUpdate() {
let $root := doc('/db/lib/repository/content/content.xml')/root
return
update value $root with $root/string()
};
local:contentUpdate()
The primary changes, compared to your original code, are:
Inserted the eXist-db syntax for your update
Prepended '/db' to your collection name, as /db is the root of the database in eXist-db; replaced the collection() call with a doc() call, since you stated you were operating on a single file, content.xml
Changed //root to /root, since "root" is the root element, so the // (descendant-or-self) axis is extraneous
Replaced updateTitle() with the actual name of the function, contentUpdate
Removed the extraneous namespace declarations
For more on why I used $root/string(), see http://community.marklogic.com/blog/text-is-a-code-smell.