How to get only first level nodes with Jsoup - java

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)

Related

XPath expression with where statement

I have xml and I want to get, using xpath expression, text from Text node only if Text_2 contains elements. Is there any possibility? I couldn't find out any.
<List>
<Response>
<Node>
<SomeNode>
<Text>text</Text>
<Text_1>text_1</Text_1>
<Text_2 value_1="some value 1" value_2="some value 2" />
</SomeNode>
</Node>
</Response>
</List>
I tried to get Text_2 elements using //*[#value_1] but I stuck and do not have any other idea
Your text says "want to get, using xpath expression, text from Text node only if Text_2 contains elements", with your given sample that would be //SomeNode[Text_2/*]/Text. For some reasons I don't understand, however, in your sample the Text_2 element doesn't have any child elements.

XPath returns for one element but doesn't return the other?

I am using Java to extract values using XPath. I was able to extract elements under the element fields but the elements under records are not returned.
XML is as follows:
<?xml version="1.0" ?>
<qdbapi>
<action>****</action>
<errcode>0</errcode>
<errtext>No error</errtext>
<qid>****</qid>
<qname>****</qname>
<table>
<fields>
<field id="19" field_type="text" base_type="text">
</field>
</fields>
<records>
<record>
<f id="6">1</f>
</record>
</records>
</table>
</qdbapi>
Code below:
XMLDOMDocObj.selectNodes("//*[local-name()='fields']")//21 fields returned
XMLDOMDocObj.selectNodes("//*[local-name()='records']")//no records are returned
XML must have a single root element; yours has two: fields and records.
Wrap them in a single common root to get the results you expect.
Also, if your XML has no namespaces, there's no reason to defeat them. Instead of
//*[local-name()='records']
use
//records
See also
How does XPath deal with XML namespaces?
Why must XML documents have a single root element?
What is the difference between root node, root element and document element in XML?

Get XML node attribute value Java

I have an XML Document which contains XML elements containing attributes from which I would like to get it's value and store it in a Hashmap.
Example:
<?xml version="1.0" encoding="UTF-8"?>
<Nodes>
<Node name="test1">
<mou>
<line3>hello</line3>
</mou>
</Node>
<Node name="test2">
<mou>
<line3>hello</line3>
</mou>
</Node>
<InputNode name="Chance">
<Test>
<RoundTo>100</RoundTo>
</Test>
</InputNode>
<InputNode name="total" />
</Nodes>
I'd like to parse this xml and retrieve the values attributes from all the elements named 'Node' and store it in a map object. So from the example above I would get
[name=test1,name=test2]
The problem is with maps the keys must be unique. How can I accomplish my goal using Java?
Sorry, I got your question wrong. You can parse the xml already. You want to store it in a map. You can create objects out of all the nodes. Node { nodeName, attribute1, attribute2} then you can save it as a map by {key,value} = {name, nodeObj}

Add XML element in a child node if parent node meets a condition

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.

Query Node in XOM

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");

Categories

Resources