I'm relatively new to XML parsers, trying to understand some java code using DOM api to parse an XML document.
I need to know what '#text' means in the following code or even what this line of code does: -
if(!ChildNode.getNodeName().equals("#text"))
{
//do something
}
According to the JavaDoc, #text is the value of the nodeName attribute for nodes implementing the Text interface.
i.e. if a node in the document is a text node (as opposed to, for example, an element), it's nodeName will be #text.
The code in question appears to be checking whether the node referenced by ChildNode is a text node before performing some action. Presumably, the action is something that can't be performed upon a text node, like querying or adding to its children.
Related
I want to list of all the leaf nodes present in an XML document. The XML is not fixed, thus the code should work for any given XML file.
Find an XML parser. Those libraries will parse the XML String for you and build an Object Oriented tree of the XML nodes (called a DOM, which stands for Document Object Model). There should be definitely a method like getChildCount(), getChildren() or isLeaf().
Take a look here: Best XML parser for Java
If you are using the DOM:
if (!myNode.hasChildNodes())
{
// found a leaf node
}
This feels like such a noob question.
I'm looking at a pile of Java code that manipulates an XML DOM. (The classes are the stock org.w3c.dom.Document and javax.xml.xpath.XPath and such that ship with JDK 7.) It has a ton of places that look like this:
String expr = "/fixed/path/through/the/hierarchy";
// actual code reuses factory instances, etc
XPath xpath = XPathFactory.newInstance().newXPath();
Node topNode = someDocumentInstance.getFirstChild();
Node node = (Node) xpath.evaluate (expr, topNode, XPathConstants.NODE);
NodeList children = node.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
if (child.getNodeName().equalsIgnoreCase("somePrefix:someTag")) {
// "return child;" or otherwise break out of the loop
}
}
And it all works. But that loop seems a tedious effort; if we're already using XPath to get a node, why then iterate over that node's children looking for a known tag?
So I tried to rewrite a section to fetch the child node directly. But querying using
String expr = "/fixed/path/through/the/hierarchy/somePrefix:someTag";
never matches anything. I've tried variations like requesting XPathConstants.NODESET or .STRING, but still no results. (There should only ever be one of these nodes anyhow.)
I feel like I'm missing something supremely obvious here, but I can't figure out why the full query fails, when the query-for-parent plus a manual loop through the children works. Is XPath testing some quality of a node beyond getNodeName() when I use a query like that?
The only theory I've come up with is that it has something to do with XML namespaces, which aren't used in this project. (There's actually a call to .setNamespaceAware(false) on the DocumentBuilderFactory instance with a comment saying "leave this off or everything everywhere breaks".)
If you're parsing without namespaces, then you should leave somePrefix out of your expression:
String expr = "/fixed/path/through/the/hierarchy/someTag";
The reason for this is that XPath performs matches on namespace and local name, not qualified name (which is what getNodeName() returns). If you put a prefix in your XPath expression, the XPath interpreter will use that to retrieve the namespace from its namespace mapping. Since you haven't given it any mappings, that will fail.
Also, you probably want to use NODESET if you're going to iterate over the child nodes.
it's not nessesary to post my full code because I have just a short questions. I'm searching with XPath in a XML Doc for a text Value. I have a XML Like
<key>Name</key>
<string>Dat Ass</string>
<key>Artist</key>
<string>Earl Sweatshirt</string>
<key>Album</key>
<string>Kitchen Cutlery</string>
<key>Kind</key>
<string>MPEG-Audiodatei</string>
I have an Expression like this:
//string[preceding-sibling::key[text()[contains(., 'Name')]]]/text()
but this gives me ALL following string-tags, I just want the first one with the Song-Title.
greets Alex
Use:
(//string[preceding-sibling::key[1] = 'Name'])[1]/text()
Alternatively, one can use a forward-only expression:
(//key[. = 'Name'])[1]/following-sibling::string[1]/text()
Do note:
This is a common error. Any expression of the kind:
//someExpr[1]
Doesn't select "the first node in the document from all nodes selected by //someExpr". In fact it can select many nodes.
The above expression selects any node that is selected by //someExpr and that is the first such child of its parent.
This is why, without brackets, the other answer to this question is generally incorrect.
You can just add another predicate [1] to select the first matching node. The nested predicate using text() should be unneccessary:
//string[preceding-sibling::key[contains(., 'Name')]][1]/text()
Another, perhaps more efficient, way to select this node would be
//key[contains(., 'Name')]/following-sibling::*[1][self::string]
This selects the first node (with any name) following the wanted key node and tests if its name is string.
I am new working in Java and XML DOM parser. I had a requirement like read the xml data and store it inform of column and rows type.
Example:sample.xml file
<staff>
<firstname>Swetha</firstname>
<lastname>EUnis</lastname>
<nickname>Swetha</nickname>
<salary>10000</salary>
</staff>
<staff>
<firstname>John</firstname>
<lastname>MAdiv</lastname>
<nickname>Jo</nickname>
<salary>200000</salary>
</staff>
i need to read this XML file and store it in the above format:
firstName,lastName,nickName,Salary
swetha,Eunis,swetha,10000
john,MAdiv,Jo,200000
Java Code:
NodeList nl= doc.getElementsByTagName("*");
for(int i=0;i< nl.getLength();i++)
{
Element section = (Element) nl.item(i);
Node title = section.getFirstChild();
while (title != null && title.getNodeType() != Node.ELEMENT_NODE)
{
title = title.getNextSibling();
if (title != null)
{
String first=title.getFirstChild().getNodeValue().trim();
if(first!=null)
{
title = title.getNextSibling();
}
System.out.print(first + ",");
} }
System.out.println("");
}//for
I did the above code, but i am not able to find the way to get the data in the above column and row format. Can any one please please kindly help me in solving my issue, i am looking into it from past many days
Since this looks like homework, I'm going to give you some hints:
The chances are that your lecturer has given you some lecture notes and/or examples on processing an XML DOM. Read them all again.
The getElementsByTagName method takes an element name as a parameter. "*" is not a valid element name, so the call won't return anything.
Your code needs to mirror the structure of the XML. The XML structure in this case consists of N staff elements, each of which contains elements named firstname, lastname, nickname and salary.
It is also possible that your lecturer expects you to use something like XSLT or an XML binding mechanism to simplify this. (Or maybe this was intended to be XMI rather than XML ... in which there are other ways to handle this ...)
I kept getElementsByTagName method parameter "*" because to read the data dynamically.
Well, it doesn't work!! The DOM getElementsByTagName method does NOT accept a pattern of any kind.
If you want to make your code generic, you can't use getElementsByTagName. You will need to walk the tree from the top, starting with the DOM's root node.
Can you please provide me with sample data.
No. Your lecturer would not approve of me giving you code to copy from. However, I will point out that there are lots of XML DOM tutorials on the web which should help you figure out what you need to do. The best thing is for you to do the work yourself. You will learn more that way ... and that is the whole point of your homework!
1. The DOM Parser will parse the entire XML file to create the DOM object.
2. You will always need to be aware of the the type of output and the structure of xml returned when a request is fired on a web-service.
3. And its Not the XML structure of a reply which is returned from the Webservice that will be dynamic, but the child elements values and attributes can be Dynamic.
4. You will need to handle this dynamic behavior with try/catch block...
For further details on DOM PARSER, see this site...
http://tutorials.jenkov.com/java-xml/dom.html
We have a large workflow of programs that parse data into XML files. We have about 14 schemes each having a different root and is made up of about 60 XSD files. Some of the schemes share similar elements but the schemes are currently being modified on weekly basis.
I have a stage (written in Java) that accepts an XML file (which might correspond to any of the 14 schemes) and reads a list of tuples of (xpaths, message) and for each xpath a flag element is inserted under the element defined by the xpath that contains the message.
<default:flag issueDateTime="2012-01-10T21:00:09" recipient="lablabla" resolvedIndicator="false" sender="SS" xmlns:default="default">
<default:flagSubject/>
<default:message>
<default:p>This element should be non empty</default:p>
</default:message>
</default:flag>
My current approach was to insert the flag element as the last child of node referenced by the xpath, that has been casing an issue. In some schemes the referenced node does accept the flag element under a sequence in an order defined by the xsd (could be middle, first or last) so adding it as last element renders the xml invalid when the element already has subelements from that sequence.
My question is, how to append an element under a sequence in a way that respects XSD defined order?
I'm currently doing this
Element flag = rawXmlDoc.createElementNS("default", "default:flag");
xpath = factory.newXPath();
xpath.setNamespaceContext(nsContext);
XPathExpression expr = xpath.compile(xpathText);
Element refNode = (Element)expr.evaluate(rawXmlDoc, XPathConstants.NODE);
if (refNode.getNodeType()==Node.ELEMENT_NODE)
refNode.appendChild(flag);
else
refNode.getParentNode().appendChild(flag);
I am hoping to get an answer using the standard DOM interface without relying on MOXy.
Why don't you use JAXB? When you use JAXB along with XJC, you can
generate Java classes from your XSD files
use JAXB to unmarshal the XML into Java objects
manipulate the XML with Java
use JAXB again to unmarshal the Java objects into valid XML
That's using standard Java XML API's but not directly DOM. However, JAXB is contained in every JDK, so you have no additional dependencies