My question is: How can I get elements directly under a specific parent element when there are other elements with the same name as a "grandchild" of the parent element.
I'm using the Java DOM library to parse XML Elements and I'm running into trouble. Here's some (a small portion) of the xml I'm using:
<notifications>
<notification>
<groups>
<group name="zip-group.zip" zip="true">
<file location="C:\valid\directory\" />
<file location="C:\another\valid\file.doc" />
<file location="C:\valid\file\here.txt" />
</group>
</groups>
<file location="C:\valid\file.txt" />
<file location="C:\valid\file.xml" />
<file location="C:\valid\file.doc" />
</notification>
</notifications>
As you can see, there are two places you can place the <file>
element. Either in groups or outside groups. I really want it structured this way because it's more user-friendly.
Now, whenever I call notificationElement.getElementsByTagName("file");
it gives me all the <file>
elements, including those under the <group>
element. I handle each of these kinds of files differently, so this functionality is not desirable.
I've thought of two solutions:
- Get the parent element of the file element and deal with it accordingly (depending on whether it's
<notification>
or<group>
. - Rename the second
<file>
element to avoid confusion.
Neither of those solutions are as desirable as just leaving things the way they are and getting only the <file>
elements which are direct children of <notification>
elements.
I'm open to IMPO comments and answers about the "best" way to do this, but I'm really interested in DOM solutions because that's what the rest of this project is using. Thanks.
There is a nice LINQ solution:
I had the same problem in one of my projects and wrote a little function which will return a
List<Element>
containing only the immediate children. Basically it checks for each node returned bygetElementsByTagName
if it's parentNode is actually the node we are searching childs of:The accepted answer by kentcdodds will return wrong results (e.g. grandchilds) if there is a childnode called "notification" - e.g. returning grandchilds when the element "group" would have the name "notification". I was facing that setup in my project, which is why I came up with my function.
You can use XPath for this, using two path to get them and process them differently.
To get the
<file>
nodes direct children of<notification>
use//notification/file
and for the ones in<group>
use//groups/group/file
.This is a simple sample:
It should output:
If you stick with the DOM API
Our first task is to get an element "Notification" (in this case the first -item (0)-) and all of its children:
(later you can work with all elements using getting all the elements).
For every child of "Notification":
you first get its type in order to see whether it is an element:
If it's the case, then you got your children "file" , that are not grand children "Notification"
and your can check them out:
and the ouptut is:
I encountered a related problem where I needed to process just the immediate child nodes even though the treatment of all "file" nodes is similar. For my solution, I compare the Element's parent node with the node that is being processed in order to determine whether the Element is an immediate child.
I realise you found something of a solution to this in May @kentcdodds but I just had a fairly similar problem which I've now found, I think (perhaps in my usecase, but not in yours), a solution to.
a very simplistic example of my XML format is shown below:-
As you can hopefully see from this snippet, the format I want can have N-levels of nesting for [relationship] nodes, so obviously the problem I had with Node.getChildNodes() was that I was getting all nodes from all levels of the hierarchy, and without any sort of hint as to Node depth.
Looking at the API for a while , I noticed there are actually two other methods that might be of some use:-
Together, these two methods seemed to offer everything that was required to get all of the immediate descendant elements of a Node. The following jsp code should give a fairly basic idea of how to implement this. Sorry for the JSP. I'm rolling this into a bean now but didn't have time to create a fully working version from picked apart code.
This code would give the following output, showing only direct child elements of the initial root node.
Hope this helps someone anyway. Cheers for the initial post.