Discussion:
[XOM-interest] How to read attribute value from Nodes class.
Kunal Chauhan
2012-05-03 12:55:27 UTC
Permalink
Hi,

How can I read attribute value of an element from Nodes class.
I am trying to implement *Streaming XQuery over Very Large Documents*.



Nodes results = XQueryUtil.*xquery*(subtree, " MY XQuery for filter"); //
transform method's part



now I get result as a Nodes.

for eg. <product id='101'></product>

so, how can I retrive id attribute from Nodes class ?



Thanks,
--
*Kunal Chauhan*
mail4ck at gmail.com
[+918655517141]
[+919904983614]
Elliotte Rusty Harold
2012-05-03 18:31:12 UTC
Permalink
Post by Kunal Chauhan
Hi,
now I get result as a Nodes.
for eg. <product id='101'></product>
so, how can I retrive id attribute from Nodes class ?
You need to select a particular Node from the Nodes you get back and
cast it to an Element. There may be more than one of these, of course.

Or you could change your XQuery to select the attribute you want in
the first place.
--
Elliotte Rusty Harold
elharo at ibiblio.org
Regier Avery J
2012-05-03 21:00:23 UTC
Permalink
I'm going to start with some context to my question.
Here's my test document:

<?xml version="1.0" encoding="UTF-8"?>
<response xmlns="http://some.namespace">
<body>
<bag id="1" rel="self" uri="/bags/1">
<name>Bag 1</name>
<item id="1" rel="self" uri="/items/1">
<name>Item 1</name>
<code>ABC1</code>
</item>
<item id="2" rel="self" uri="/items/2">
<name>Item 2</name>
<code>ABC2</code>
</item>
</bag>
</body>
</response>

Here's my path:
//a:*[not(self::code)]|//@id

I have bound 'a' to http://some.namespace in the XPathContext.

private Nodes query(Document doc, String xpath, XPathContext xpathContext)
throws ContextException {
Nodes nodes;
try {
nodes = doc.query(xpath, xpathContext);
} catch(nu.xom.XPathException e) {
// throw a ContextException
}
return nodes;
}

I need to select all elements in the document that aren't 'a:code' and select all the 'id' attributes but not any of the others. This is just one example. I am going to limit the response xml to only what the path 'passes'.

As far as I can tell from various books and documentation, //* is not supposed to select anything on the namespace axis. Nevertheless, it appears that XOM is doing exactly that, and I get the following error.

Caused by: nu.xom.XPathException: XPath error: No Such Function {http://axiom.deere.com/Platform/Data/Services}:not
at nu.xom.Node.query(Unknown Source)
at com.deere.axiom.rest.followpass.domain.XomFollowPass.query(XomFollowPass.java:159)
... 28 more
Caused by: nu.xom.jaxen.UnresolvableException: No Such Function {http://axiom.deere.com/Platform/Data/Services}:not
at nu.xom.jaxen.SimpleFunctionContext.getFunction(Unknown Source)
at nu.xom.jaxen.ContextSupport.getFunction(Unknown Source)
at nu.xom.jaxen.Context.getFunction(Unknown Source)
at nu.xom.jaxen.expr.DefaultFunctionCallExpr.evaluate(Unknown Source)
at nu.xom.jaxen.expr.DefaultPredicate.evaluate(Unknown Source)
at nu.xom.jaxen.expr.PredicateSet.applyPredicate(Unknown Source)
at nu.xom.jaxen.expr.PredicateSet.evaluatePredicates(Unknown Source)
at nu.xom.jaxen.expr.DefaultNameStep.evaluate(Unknown Source)
at nu.xom.jaxen.expr.DefaultLocationPath.evaluate(Unknown Source)
at nu.xom.jaxen.expr.DefaultAbsoluteLocationPath.evaluate(Unknown Source)
at nu.xom.jaxen.expr.DefaultUnionExpr.evaluate(Unknown Source)
at nu.xom.jaxen.expr.DefaultXPathExpr.asList(Unknown Source)
at nu.xom.jaxen.BaseXPath.selectNodesForContext(Unknown Source)
at nu.xom.jaxen.BaseXPath.selectNodes(Unknown Source)
at nu.xom.JaxenConnector.selectNodes(Unknown Source)
... 30 more

I've tried everything I can think of to modify the xpath statement to ignore nodes on the namespace axis for this query to no avail.

Ideas on how to work around this? Is this a bug or actually correct according to the spec?

Thanks,
Avery J. Regier
RegierAveryJ at JohnDeere.com
Michael Kay
2012-05-03 22:01:39 UTC
Permalink
I don't know what leads you to imagine that this is anything to do with
the namespace axis. However, it's a pretty strange error.

Firstly, your expression should be

//a:*[not(self::a:code)]|//@id

rather than

//a:*[not(self::code)]|//@id


However, that doesn't seem to be what it's complaining about. For some reason the processor is looking for a function whose local name is "not" and whose namespace URI is http://axiom.deere.com/Platform/Data/Services. The only possible cause for that I can imagine is that you have somehow set the default namespace for functions to "http://axiom.deere.com/Platform/Data/Services". I can't think of any reason you would want to do that.

Michael Kay
Saxonica
Post by Regier Avery J
I'm going to start with some context to my question.
<?xml version="1.0" encoding="UTF-8"?>
<response xmlns="http://some.namespace">
<body>
<bag id="1" rel="self" uri="/bags/1">
<name>Bag 1</name>
<item id="1" rel="self" uri="/items/1">
<name>Item 1</name>
<code>ABC1</code>
</item>
<item id="2" rel="self" uri="/items/2">
<name>Item 2</name>
<code>ABC2</code>
</item>
</bag>
</body>
</response>
I have bound 'a' to http://some.namespace in the XPathContext.
private Nodes query(Document doc, String xpath, XPathContext xpathContext)
throws ContextException {
Nodes nodes;
try {
nodes = doc.query(xpath, xpathContext);
} catch(nu.xom.XPathException e) {
// throw a ContextException
}
return nodes;
}
I need to select all elements in the document that aren't 'a:code' and select all the 'id' attributes but not any of the others. This is just one example. I am going to limit the response xml to only what the path 'passes'.
As far as I can tell from various books and documentation, //* is not supposed to select anything on the namespace axis. Nevertheless, it appears that XOM is doing exactly that, and I get the following error.
Caused by: nu.xom.XPathException: XPath error: No Such Function {http://axiom.deere.com/Platform/Data/Services}:not
at nu.xom.Node.query(Unknown Source)
at com.deere.axiom.rest.followpass.domain.XomFollowPass.query(XomFollowPass.java:159)
... 28 more
Caused by: nu.xom.jaxen.UnresolvableException: No Such Function {http://axiom.deere.com/Platform/Data/Services}:not
at nu.xom.jaxen.SimpleFunctionContext.getFunction(Unknown Source)
at nu.xom.jaxen.ContextSupport.getFunction(Unknown Source)
at nu.xom.jaxen.Context.getFunction(Unknown Source)
at nu.xom.jaxen.expr.DefaultFunctionCallExpr.evaluate(Unknown Source)
at nu.xom.jaxen.expr.DefaultPredicate.evaluate(Unknown Source)
at nu.xom.jaxen.expr.PredicateSet.applyPredicate(Unknown Source)
at nu.xom.jaxen.expr.PredicateSet.evaluatePredicates(Unknown Source)
at nu.xom.jaxen.expr.DefaultNameStep.evaluate(Unknown Source)
at nu.xom.jaxen.expr.DefaultLocationPath.evaluate(Unknown Source)
at nu.xom.jaxen.expr.DefaultAbsoluteLocationPath.evaluate(Unknown Source)
at nu.xom.jaxen.expr.DefaultUnionExpr.evaluate(Unknown Source)
at nu.xom.jaxen.expr.DefaultXPathExpr.asList(Unknown Source)
at nu.xom.jaxen.BaseXPath.selectNodesForContext(Unknown Source)
at nu.xom.jaxen.BaseXPath.selectNodes(Unknown Source)
at nu.xom.JaxenConnector.selectNodes(Unknown Source)
... 30 more
I've tried everything I can think of to modify the xpath statement to ignore nodes on the namespace axis for this query to no avail.
Ideas on how to work around this? Is this a bug or actually correct according to the spec?
Thanks,
Avery J. Regier
RegierAveryJ at JohnDeere.com
_______________________________________________
XOM-interest mailing list
XOM-interest at lists.ibiblio.org
http://lists.ibiblio.org/mailman/listinfo/xom-interest
Elliotte Rusty Harold
2012-05-03 22:04:34 UTC
Permalink
On Thu, May 3, 2012 at 5:00 PM, Regier Avery J
Post by Regier Avery J
Caused by: nu.xom.XPathException: XPath error: No Such Function {http://axiom.deere.com/Platform/Data/Services}:not
? ? ? ?at nu.xom.Node.query(Unknown Source)
? ? ? ?at com.deere.axiom.rest.followpass.domain.XomFollowPass.query(XomFollowPass.java:159)
? ? ? ?... 28 more
That's weird. There's certainly a bug here, but it may or may not be a
bug in XOM; and in either case it's almost certainly not what you
think it is. Can you narrow this down to a self-contained test case. I
suspect if you do so, the problem will make itself apparent, but if
not, send that test case here and I'll check it out.

Also, do you have any idea where the URL
http://axiom.deere.com/Platform/Data/Services is coming from? That's
the biggest clue.
--
Elliotte Rusty Harold
elharo at ibiblio.org
Regier Avery J
2012-05-03 22:40:36 UTC
Permalink
Yes. That URL I was trying to replace with http://some.namespace for your consumption. Treat it as if it were the same namespace as in the root element. I tried using item::a:code but get the exact same error.

- Avery
Post by Elliotte Rusty Harold
On Thu, May 3, 2012 at 5:00 PM, Regier Avery J
Post by Regier Avery J
Caused by: nu.xom.XPathException: XPath error: No Such Function {http://axiom.deere.com/Platform/Data/Services}:not
at nu.xom.Node.query(Unknown Source)
at com.deere.axiom.rest.followpass.domain.XomFollowPass.query(XomFollowPass.java:159)
... 28 more
That's weird. There's certainly a bug here, but it may or may not be a
bug in XOM; and in either case it's almost certainly not what you
think it is. Can you narrow this down to a self-contained test case. I
suspect if you do so, the problem will make itself apparent, but if
not, send that test case here and I'll check it out.
Also, do you have any idea where the URL
http://axiom.deere.com/Platform/Data/Services is coming from? That's
the biggest clue.
--
Elliotte Rusty Harold
elharo at ibiblio.org
_______________________________________________
XOM-interest mailing list
XOM-interest at lists.ibiblio.org
http://lists.ibiblio.org/mailman/listinfo/xom-interest
Elliotte Rusty Harold
2012-05-03 23:17:17 UTC
Permalink
On Thu, May 3, 2012 at 6:40 PM, Regier Avery J
Yes. That URL I was trying to replace with http://some.namespace for your consumption. ?Treat it as if it were the same namespace as in the root element. I tried using item::a:code but get the exact same error.
- Avery
Again, the problem is not what you think it is. If you provide a
complete, self-contained example we can probably figure out what's
wrong.
--
Elliotte Rusty Harold
elharo at ibiblio.org
Regier Avery J
2012-05-04 13:20:55 UTC
Permalink
Here's as simple a test case as I can muster.

import java.io.IOException;
import java.io.StringReader;

import nu.xom.Builder;
import nu.xom.Document;
import nu.xom.Nodes;
import nu.xom.ParsingException;
import nu.xom.ValidityException;
import nu.xom.XPathContext;

import org.junit.Test;
import static org.junit.Assert.assertEquals;


public class ERHTest {
// This test succeeds
@Test
public void testNot() throws ValidityException, ParsingException, IOException {
Document doc = new Builder().build(new StringReader("<hi/>"));
Nodes query = doc.query("//*[not(self::human)]", XPathContext.makeNamespaceContext(doc.getRootElement()));
assertEquals(1, query.size());
}

// This test fails with
// nu.xom.XPathException: XPath error: No Such Function {there://mr.space/alien}:not
@Test
public void testNotWithNamespace() throws ValidityException, ParsingException, IOException {
Document doc = new Builder().build(new StringReader("<hi xmlns='there://mr.space/alien'/>"));
XPathContext context = XPathContext.makeNamespaceContext(doc.getRootElement());
context.addNamespace("a", doc.getRootElement().getNamespaceURI());
Nodes query = doc.query("//*[not(self::a:human)]", context);
assertEquals(1, query.size());
}

// This test succeeds
@Test
public void testNotWithNamespaceWorkaround() throws ValidityException, ParsingException, IOException {
Document doc = new Builder().build(new StringReader("<hi xmlns='there://mr.space/alien'/>"));
XPathContext context = XPathContext.makeNamespaceContext(doc.getRootElement());
context.addNamespace("a", doc.getRootElement().getNamespaceURI());
context.addNamespace("f", "");
Nodes query = doc.query("//*[f:not(self::a:human)]", context);
assertEquals(1, query.size());
}
}

nu.xom.XPathException: XPath error: No Such Function {there://mr.space/alien}:not
at nu.xom.Node.query(Unknown Source)
at ERHTest.testNotWithNamespace(ERHTest.java:30)
<snip>
Caused by: nu.xom.jaxen.UnresolvableException: No Such Function {there://mr.space/alien}:not
at nu.xom.jaxen.SimpleFunctionContext.getFunction(Unknown Source)
at nu.xom.jaxen.ContextSupport.getFunction(Unknown Source)
at nu.xom.jaxen.Context.getFunction(Unknown Source)
at nu.xom.jaxen.expr.DefaultFunctionCallExpr.evaluate(Unknown Source)
at nu.xom.jaxen.expr.DefaultPredicate.evaluate(Unknown Source)
at nu.xom.jaxen.expr.PredicateSet.applyPredicate(Unknown Source)
at nu.xom.jaxen.expr.PredicateSet.evaluatePredicates(Unknown Source)
at nu.xom.jaxen.expr.DefaultNameStep.evaluate(Unknown Source)
at nu.xom.jaxen.expr.DefaultLocationPath.evaluate(Unknown Source)
at nu.xom.jaxen.expr.DefaultAbsoluteLocationPath.evaluate(Unknown Source)
at nu.xom.jaxen.expr.DefaultXPathExpr.asList(Unknown Source)
at nu.xom.jaxen.BaseXPath.selectNodesForContext(Unknown Source)
at nu.xom.jaxen.BaseXPath.selectNodes(Unknown Source)
at nu.xom.JaxenConnector.selectNodes(Unknown Source)
... 24 more

While debugging I can see that the SimpleFunctionContext object has a function list that includes not, but it has an empty namespace. It appears the namespace of the root node of the XML document doesn't match the namespace of the 'not' function, resulting in the 'not' function not being found.

Why should I have to declare a namespace for functions? Does the XPath spec require this?

Would specifying a namespace for the not() function work across other XPath implementations?

Avery J. Regier
RegierAveryJ at JohnDeere.com
Elliotte Rusty Harold
2012-05-05 00:22:01 UTC
Permalink
That is very strange. I can confirm the behavior you observed.
Probably a bug in Jaxen. Let me see if I can figure this out. Thanks
for the report.
--
Elliotte Rusty Harold
elharo at ibiblio.org
Elliotte Rusty Harold
2012-05-05 00:39:13 UTC
Permalink
OK. I think I see what's happening. The setup you have binds the empty
string prefix to there://mr/space.alien and jaxen looks it up
regardless. Arguably it's a bug in both jaxen and XOM. I'll fix it
soon.
--
Elliotte Rusty Harold
elharo at ibiblio.org
Elliotte Rusty Harold
2012-05-05 00:50:38 UTC
Permalink
I've fixed the one you reported as a bug in my local client. I think
your workaround should also fail:

public void testNotWithNamespaceWorkaround() throws
ParsingException, IOException {

Document doc = new Builder().build(new StringReader("<root
xmlns='http://www.example.org'/>"));
XPathContext context =
XPathContext.makeNamespaceContext(doc.getRootElement());
context.addNamespace("a", doc.getRootElement().getNamespaceURI());
context.addNamespace("f", "");
Nodes query = doc.query("//*[f:not(self::a:test)]", context);
assertEquals(1, query.size());

}

I.e. "//*[f:not(self::a:test)]" is not a correct XPath 1.0 expression,
at least not when f is bound to the empty string.

Michael, what do you think?
--
Elliotte Rusty Harold
elharo at ibiblio.org
Elliotte Rusty Harold
2012-05-05 00:55:34 UTC
Permalink
Actually, I can't find any language in the XPath spec that says
binding a prefix to the empty string and then using it to qualify a
default function is clearly wrong. It's still damn weird though.
--
Elliotte Rusty Harold
elharo at ibiblio.org
Michael Kay
2012-05-05 09:03:56 UTC
Permalink
I suspect Jaxen was written with some awareness of the way the spec
moved after XPath 1.0, but without going all the way to 2.0. Further
complicating matters is that the W3C specs have nothing to say about
what APIs can do; and the 1.0 spec has only the haziest description of
the static context.

XPath 1.0 explains how a QName in a NodeTest is expanded (no prefix
means no namespace). But it doesn't say how a QName in a function name
is expanded. I think one can assume that the authors intended system
functions such as "not" to be in no namespace, and it pretty well
follows that function names can't be expanded using the default
namespace because that would make system functions inaccessible.

Generally XPath 1.0 is a pretty lightweight spec which is probably why
it has been so successful. It doesn't waste time discussing edge cases,
which can make it very frustrating for implementors.

Michael Kay
Saxonica
Post by Elliotte Rusty Harold
I've fixed the one you reported as a bug in my local client. I think
public void testNotWithNamespaceWorkaround() throws
ParsingException, IOException {
Document doc = new Builder().build(new StringReader("<root
xmlns='http://www.example.org'/>"));
XPathContext context =
XPathContext.makeNamespaceContext(doc.getRootElement());
context.addNamespace("a", doc.getRootElement().getNamespaceURI());
context.addNamespace("f", "");
Nodes query = doc.query("//*[f:not(self::a:test)]", context);
assertEquals(1, query.size());
}
I.e. "//*[f:not(self::a:test)]" is not a correct XPath 1.0 expression,
at least not when f is bound to the empty string.
Michael, what do you think?
Dave Pawson
2012-05-05 13:47:57 UTC
Permalink
Post by Michael Kay
Generally XPath 1.0 is a pretty lightweight spec which is probably why
it has been so successful. It doesn't waste time discussing edge cases,
which can make it very frustrating for implementors.
Michael Kay
Saxonica
There's surely a lesson there Mike? Not sure if James did it
deliberately, but the uptake (IMHO) defines a success?

Perhaps compare this with xlink, xpointer which go the other way?

regards
--
Dave Pawson
XSLT XSL-FO FAQ.
Docbook FAQ.
http://www.dpawson.co.uk
Elliotte Rusty Harold
2012-05-05 16:34:53 UTC
Permalink
FYI, this turns out to be a bug in jaxen in variable names as well.
XOM doesn't support variable names in XPath so it doesn't come up
here. The bug is fixed in jaxen at head.

I have to fix one other bug in jaxen and then I'll push a new release
of jaxen, and then a new release of XOM soon after.
--
Elliotte Rusty Harold
elharo at ibiblio.org
Loading...