I am querying document in XOM, getting a Node, and then querying this Node for another Node. However, querying Node behaves like it's querying whole document, not only this node.
XML is like this:
<root>
<someotherstuff>
<DifferentNode>
<Value1>different-value1</Value1>
</DifferentNode>
<Node>
<Node>
<Value1>value1</Value1>
<Value2>value2</Value2>
</Node>
<Node>
<Value1>value3</Value1>
<Value2>value4</Value2>
</Node>
<!-- more Node's -->
</Node>
</someotherstuff>
</root>
And I'm doing this:
Nodes nodes = document.query("//Node/Node", X_PATH_CONTEXT);
Node node = nodes.get(0);
Nodes innerNodes = node.query("/Value1");
And innerNodes contains 0 children. When I change "/Value1" to "//Value1" (slash added) then I'm getting different-value1, so it looks like it's querying whole document, instead of my selected Node.
How can I query specific Node in XOM?
When your query starts with a single slash then this looks for the document root node with the given name. Two slashes in contrast means to look for all ancestors of the given name. Your query should work if you simply omit the leading slash:
Nodes innerNodes = node.query("Value1");
Related
I am trying to get the XML value of a node.
To get the Nodelist i am doing this
NodeList list = (NodeList) doc.getElementsByTagName("response")
To get particular Node I am doing:
list.item(index);
From the node i can get the text content of the node but I don't know how to get the XML String value of a node.
For example:
<add job="351">
<test>
<tag>foobar</tag>
<tag>foobar2</tag>
</test>
</add>
I can pick the node with tag "test". Now from the Node i want output like this:
<test>
<tag>foobar</tag>
<tag>foobar2</tag>
</test>
Any help is appreciated.
I have following XML tree and I'm using Jsoup to parse it.
<?xml version="1.0" encoding="UTF-8" ?>
<nodes>
<node>
<name>NODE 1</name>
<value1>
<value1>NODE 1 VALUE 1</value1>
</value1>
<nodes>
<node>
<name>NODE 1 CHILD</name>
<value1>NODE 1 CHILD VALUE 1</value1>
</node>
</nodes>
</node>
<node>
<name>NODE 2</name>
<value1>NODE 2 VALUE 1</value1>
</node>
</nodes>
However when I try to get only first level of node-elements. It returns all elements including children nodes, and it is doing it correctly, because clearly child elements also match my query.
Elements elements = data.select("nodes > node");
Is there any way to get just first level node-elements without adding additional level information to XML data?
You can do something like this:
Elements elements = data.select("nodes").first().select("> node");
This will work as well:
Elements elements = data.select("> nodes > node");
but only if you've used Jsoup.parse(xml, "", Parser.xmlParser()) to parse the XML and the XML is indeed as you've specified in your question (<nodes> is the root element)
I have a very simple question for you experts of XML.
I want to add a new Element beside tuple_centre_name, with the same tag and different value, only if the username have a value I want, and another tuple_centre_name with the same value, here amministrazione, does NOT exist.
I ask you because I find difficult to reach that element, check if another tuple_centre_name exists and then check the parent attribute.
I'm using DOM in JAVA.
Thanks for helping me.
<?xml version="1.0" encoding="UTF-8" standalone="no"?><accounts>
<account>
<username>fabio</username>
<password>123456</password>
<node>
<tuple_centre_name>amministrazione</tuple_centre_name>
<port>NP</port>
</node>
</account>
Example is shown here. Request: add a new tuple_centre_name named something else only if it does not already exist inside the element named fabio. Here, is the result I want:
<?xml version="1.0" encoding="UTF-8" standalone="no"?><accounts>
<account>
<username>fabio</username>
<password>123456</password>
<node>
<tuple_centre_name>amministrazione</tuple_centre_name>
<tuple_centre_name>Something else</tuple_centre_name> //ok because `fabio` as username is fine for me
<port>NP</port>
</node>
</account>
You want XPath for this:
Document document = /* ... */;
final String username = "fabio";
XPathVariableResolver resolver = new XPathVariableResolver() {
#Override
public Object resolveVariable(QName varName) {
return varName.getLocalPart().equals("user") ? username : null;
}
};
Element newElement = document.createElement("tuple_centre_name");
newElement.appendChild(document.createTextNode("amministraione"));
XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setXPathVariableResolver(resolver);
Node tupleCentreNameNode = (Node) xpath.evaluate(
"//account[username[text()=$user]]/node/tuple_centre_name",
document,
XPathConstants.NODE);
tupleCentreNameNode.getParentNode().insertBefore(newElement,
tupleCentreNameNode.getNextSibling());
XPath usually looks like a directory path, which is where the account/node/tuple_centre_name part comes from. The two slashes at the start (//account) means "any account element, any number of levels deep in the document."
The account[username[text()=$user]] selector means "an account element which contains a username element whose text matches the XPath variable 'user'." XPath variables can be defined externally with an XPathVariableResolver. While it is possible to hard-code the username value in the XPath expression, you would need to escape various characters, including quotes and characters which are special in XML; passing the username as an XPath variable guarantees it will be correct.
My XML structure is as under
<Employee>
<categoryType>Name</categoryType>
<groupNames>
<name>ABC</name>
<name>XYZ</name>
<name>PQR</name>
</groupNames>
</Employee>
I am trying to get hold of the child nodes by searching for parent node (categoryType = Name ).
Tried using all the following combinations , but none of them return the child nodes.
//*[contains(#categoryType,'Name')]/groupNames
Employee/*(#categoryType,'Name')/groupNames
Any suggestions would be appreciated.
You are matching an attribute categoryType which doesn't exist. You have to match an element. Replace #categoryType for categoryType and you will have a different result.
This:
//*[contains(categoryType,'Name')]/groupNames
will get the categoryType node. And this:
//*[contains(categoryType,'Name')]/groupNames/name
will return a node-set with all three names.
I have a function which converts a string to DOM, and then uses javax.xml.xpath.XPathFactory on the DOM object to pull data.
The XPathFactory works fine for the following string
<root><test><name>A</name></test><test><name>B</name></test></root>
but it fails if I have spaces between tags
<root> <test> <name>A</name> </test> <test> <name>B</name> </test></root>
I'm using XpathFactory to ready the values "A" and "B" from the DOM.
Can anyone tell me exactly why is XpathFactory failing when the string has spaces in between tags.
Thanks
--SD
The XPath is correct and works ok, I think that the problem is that
list.item(i).getChildNodes().item(0).getTextContent());
gets the first child node of the node matching the XPath, that in the case of the XML with the spaces is the spaces right after <employee>, whereas in the case of the XML without the spaces is the <name> element.
In other words in the case with spaces the child nodes of the first employee element are (one per line):
[spaces]
<name> . . . </name>
[spaces]
<company-no> . . . </company-no>
[spaces]
<chunk-id> . . .</chunk-id>
in the case without spaces they are:
<name> . . . </name>
<company-no> . . . </company-no>
<chunk-id> . . .</chunk-id>
and so in the first case the child nodes you need are 1, 3 and 5, in the second case are 0, 1 and 2.
I think you should modify this piece of code:
System.out.println("Name: " +list.item(i).getChildNodes().item(0).getTextContent());
System.out.println("Company: "+list.item(i).getChildNodes().item(1).getTextContent());
System.out.println("Chunk: "+list.item(i).getChildNodes().item(2).getTextContent());
to either use other XPaths to get the name, company and chunk sub-nodes or to skip the child nodes containing spaces.
/root/test/name
or even just
//name
optionally, directly get the child text nodes
//name/text()