From: Todd G. <tod...@gm...> - 2012-04-22 20:03:12
|
I have this XQuery which counts the number of nodes with the same name within a collection of documents: xquery version "1.0"; declare namespace util="http://exist-db.org/xquery/util"; declare namespace log4j="http://jakarta.apache.org/log4j/"; declare namespace fo="http://www.w3.org/1999/XSL/Format"; declare namespace context="http://www.springframework.org/schema/context"; declare namespace http-conf=" http://cxf.apache.org/transports/http/configuration"; declare namespace jaxws="http://cxf.apache.org/jaxws"; <names> { for $name in distinct-values(collection('/db/obpi-app/obpi-app-xml')//*/node-name(.)) return <name count="{util:eval(concat('count(collection("','/db/obpi-app/obpi-app-xml','")//',$name,')'))}">{$name}</name> } </names> With the declared namespace explicitly called out, I get this error: Error while evaluating expression: count(collection("/db/obpi-app/obpi-app-xml")//jaxws:endpoint). XPST0081: No namespace defined for prefix jaxws [at line 11, column 22] Is there a way to write this XQuery so it doesn't required a priori knowledge of the namespaces within a collection? |
From: Joe W. <jo...@gm...> - 2012-04-22 20:53:14
|
Hi Todd, > With the declared namespace explicitly called out, I get this error: > > Error while evaluating expression: > count(collection("/db/obpi-app/obpi-app-xml")//jaxws:endpoint). XPST0081: No > namespace defined for prefix jaxws [at line 11, column 22] > > Is there a way to write this XQuery so it doesn't required a priori > knowledge of the namespaces within a collection? First, I'm a bit surprised that you're getting this error, since you clearly have declared the namespace and util:eval() is supposed to inherit the namespace declarations according to the docs: "The query inherits the current execution context, i.e. all namespace declarations and variable declarations are visible from within the inner expression." http://exist-db.org/exist/functions/util/eval But that said, here are some pointers: 1. If you're set on using util:eval(), just construct the 'declare namespace' declaration using concat(). For a code example of this strategy, see the indexes:get-namespace-declaration-from-node-name() function in line 547-559 in http://exist.svn.sourceforge.net/viewvc/exist/trunk/eXist/webapp/admin/indexes.xqm?revision=16274&view=markup. This is used for the Admin > Browse Indexes page (http://localhost:8080/exist/admin/admin.xql?panel=indexes), which has to query elements in arbitrary namespaces. 2. It's actually best practice to avoid util:eval unless it's really necessary (and it usually isn't). Here, in fact, it is not necessary. Just use the same strategy you do in your distinct-values() expression instead: count(collection('/db/obpi-app/obpi-app-xml')//*[node-name(.) = $name])) If you have follow up questions on this, could you tell us which version of eXist you're using? Cheers, Joe |
From: Todd G. <tod...@gm...> - 2012-04-22 21:45:28
|
I am using version 2.0-tech-preview. (Following is the content from two emails I sent directly to Joe) 1) The error I am seeing occurs when the namespaces are not declared. The code example I gave was after I had executed the XQuery in eXide five separate times getting this error 5 times and adding the appropate namespace 5 times (requiring me to go to Google for the URI as I couldn't figure out how to extract it from the database easily). The end result is an XQuery with all the namespaces declared. This is a process I would like to avoid when dealing with generic collections of unknown content. This purpose of this XQuery is to produce a summary by which I can analyze said generic collection. The use of util:eval is dramatically faster than using the predicate *[node-name(.) = $name]. When processing a large collection, eXist will churn forever using the //*[node-name(.)] form. For performance reasons I would say the use of util:eval() is necessary. In order to append namespace declarations to the beginning of the eval string, I would have to know about them ahead of time. The XML stored in the database knows what the namespace is already. I have a QName as a distinct-value no longer associated with the multiple elements of that name in the database. How do I query the database for the namespace URI given this string? I am now reviewing the code you referenced in indices.xqm, specifically the indexes:get-namespace-uri-from-node-name($node-name, $collection) function. I think I can use this to react to a node-name possessing a prefix and inject the namespace declaraction accordingly. Thanks for the pointer to this reference. 2) Another issue I am having is that I'm not getting distinct-values. I am seeing multiple instances of the same QName in the list. I am running this: for $name in distinct-values(collection('/db/obpi-app/obpi-app-xml')//*/node-name(.)) order by upper-case($name) return concat($name,", ") and getting what I think is one unique name per document. I tried adding parens around the node selection list this: distinct-values((collection('/db/obpi-app/obpi-app-xml')//*)/node-name(.)) but this didn't work like I thought it would. Todd |
From: Todd G. <tod...@gm...> - 2012-04-23 01:08:40
|
I can't figure out why distinct-values(//*/node-name(.)) fails to produce a list of unique node names. Is it a bug? Also, regarding the original topic, it seems that there is another class of nodes in the database that used the document's default namespace, so the eval() attempts to count these nodes and the count returns zero. Take a look below in the data for the node name 'beans' node referencing a document defined as <beans xmlns=" http://www.springframework.org/schema/beans"/>, so what must I do to get the XQuery to count these nodes? The code now looks like this: xquery version "1.0"; declare namespace util="http://exist-db.org/xquery/util"; declare namespace log4j="http://jakarta.apache.org/log4j/"; declare namespace fo="http://www.w3.org/1999/XSL/Format"; declare namespace context="http://www.springframework.org/schema/context"; declare namespace http-conf=" http://cxf.apache.org/transports/http/configuration"; declare namespace jaxws="http://cxf.apache.org/jaxws"; let $nodes := collection('/db/obpi-app')//* let $node-names := for $name in distinct-values($nodes/node-name(.)) order by string($name) return string($name) let $names := <names count-nodes="{count($nodes)}" count-names="{count($node-names)}"> { for $name in $node-names return <name count="{util:eval(concat('count(collection("','/db/obpi-app','")//',$name,')'))}">{$name}</name> } </names> return xmldb:store('/db','obpi-app-names.xml',$names) and the data looks like this: <names count-nodes="126492" count-names="2228"> <name count="2">FlexMonkey</name> <name count="1">MinOrMaxStates</name> <name count="1">Test</name> <name count="1">TestCase</name> <name count="1">TestSuite</name> <name count="1">TestSuiteFile</name> <name count="6">UIEvent</name> <name count="0">a</name> <name count="0">a</name> <name count="1">account</name> <name count="2">action</name> <name count="2">action</name> <name count="12">adapter</name> <name count="12">adapter</name> <name count="12">adapter</name> <name count="12">adapter</name> <name count="12">adapter</name> <name count="12">adapter</name> <name count="12">adapter</name> <name count="1">addAttachment</name> <name count="5">agency</name> <name count="5">agency_authority</name> <name count="1">agency_carrier_appointment</name> <name count="11">agency_lines_of_business</name> <name count="21">agent</name> <name count="21">agent</name> <name count="21">agent</name> <name count="21">agent</name> <name count="21">agent</name> <name count="21">agent</name> <name count="3">agentBindAllQuotes</name> <name count="3">agentBindAllQuotes</name> <name count="3">agentBinderLetterEnabled</name> <name count="3">agentBinderLetterEnabled</name> <name count="3">agentBinderLetterEnabled</name> <name count="3">agentBindingFormEnabled</name> <name count="3">agentBindingFormEnabled</name> <name count="3">agentBindingFormEnabled</name> <name count="6">allowExpirationDateAfterEffectiveDate</name> <name count="6">allowExpirationDateAfterEffectiveDate</name> <name count="6">allowExpirationDateAfterEffectiveDate</name> <name count="22">appender</name> <name count="26">appender-ref</name> <name count="26">appender-ref</name> <name count="3">arg</name> <name count="2">ascender</name> <name count="2">ascender</name> <name count="512">assigned_authorization</name> <name count="223">assigned_role</name> <name count="223">assigned_role</name> <name count="223">assigned_role</name> <name count="223">assigned_role</name> <name count="223">assigned_role</name> <name count="223">assigned_role</name> <name count="1">associationCode</name> <name count="1">attachment</name> <name count="78">auth-filter</name> <name count="78">auth-filter</name> <name count="78">auth-filter</name> <name count="78">auth-filter</name> <name count="78">auth-filter</name> <name count="0">b</name> <name count="0">b</name> <name count="0">b</name> <name count="2">bbox</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">bean</name> <name count="0">beans</name> <name count="0">beans</name> <name count="0">beans</name> <name count="0">beans</name> <name count="0">beans</name> <name count="0">beans</name> <name count="0">beans</name> <name count="0">beans</name> <name count="0">beans</name> <name count="0">beans</name> <name count="0">beans</name> <name count="0">beans</name> <name count="1290">bf</name> <name count="1290">bf</name> <name count="2">bfranges</name> <name count="2">bfranges</name> <name count="3">bindCoverLetterTemplate</name> <name count="3">bindCoverLetterTemplate</name> <name count="3">bindCoverLetterTemplate</name> <name count="1">bindTask</name> <name count="3">bindTemplate</name> <name count="3">bindTemplate</name> <name count="3">bindTemplate</name> <name count="3">binderLetterEnabled</name> <name count="3">binderLetterEnabled</name> <name count="3">binderLetterEnabled</name> <name count="3">bindingFormEnabled</name> <name count="3">bindingFormEnabled</name> <name count="3">bindingFormEnabled</name> <name count="3">body</name> ... </names> |
From: Joe W. <jo...@gm...> - 2012-04-23 16:28:21
|
Hi Todd, > I can't figure out why distinct-values(//*/node-name(.)) fails to produce a list of unique node names. Is it a bug? Strange, indeed. Can you send a small test (data + query) we can run to reproduce what you are seeing? Ideally, the smallest, clearest data + query that shows the problem. Also, you asked: > How do I query the database for the namespace URI given this string? Query for a namespace? What do you mean? (If you haven't figured out how to do what you wanted to do, that is.) Cheers, Joe |