Child elements of DOM - java

I have this XML file:
<scene>
<texture file="file1.dds"/>
<texture file="file2.dds"/>
...
<node name="cube">
<texture name="stone" unit="0" sampler="anisotropic"/>
</node>
</scene>
I need all child element of 'scene' that are named "texture", but with this code:
Element rootNode = document.getDocumentElement();
NodeList childNodes = rootNode.getElementsByTagName("texture");
for (int nodeIx = 0; nodeIx < childNodes.getLength(); nodeIx++) {
Node node = childNodes.item(nodeIx);
if (node.getNodeType() == Node.ELEMENT_NODE) {
// cool stuff here
}
}
i also get the 'texture' elements which are inside 'node'.
How can i filter these out? Or how can i get only the elements that are direct childs of 'scene'?

You can do it using Xpath, consider the following example taken from the JAXP Specification 1.4 (which I recommend you to consult for this):
// parse the XML as a W3C Document
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
org.w3c.Document document = builder.parse(new File("/widgets.xml"));
// evaluate the XPath expression against the Document
XPath xpath = XPathFactory.newInstance().newXPath();
String expression = "/widgets/widget[#name='a']/#quantity";
Double quantity = (Double) xpath.evaluate(expression, document, XPathConstants.NUMBER);

I found myself a solution that works fine:
Element parent = ... ;
String childName = "texture";
NodeList childs = parent.getChildNodes();
for (int nodeIx = 0; nodeIx < childs.getLength(); nodeIx++) {
Node node = childs.item(nodeIx);
if (node.getNodeType() == Node.ELEMENT_NODE
&& node.getNodeName().equals(name)) {
// cool stuff here
}
}

Related

Parsing an XML document to get node values

I have an xml structure as below:
String attributesXML="<entry>
<value>
<List>
<String>Rob</String>
<String>Mark</String>
<String>Peter</String>
<String>John</String>
</List>
</value>
</entry>"
I want to fetch the values Rob,Mark,Peter,John. I can get the nodes starting from entry node(Code below). Problem is i don't know what will be the child node names under entry node. Starting from entry node i need to keep drilling down until I find the values. I have written a method getChildNodeValue() but it doesn't give me the required Output. It does print what i need but it prints some extra stuff as well. I need to return the values as a csv from this method getChildNodeValue().
Getting Entry Node:
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(attributesXML));
Document doc = db.parse(is);
NodeList nodes = doc.getElementsByTagName("entry");
for (int i = 0; i < nodes.getLength(); i++) {
if(nodes.item(i).hasChildNodes()){
getChildNodeValue(nodes.item(i));
}
}
public static void getChildNodeValue(Node node) {
System.out.println("Start Node: "+node.getNodeName());
NodeList nodeList = node.getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node currentNode = nodeList.item(i);
while(currentNode.hasChildNodes()){
System.out.println("Current Node: "+currentNode.getNodeName());
nodeList = currentNode.getChildNodes();
for(int j=0;j<nodeList.getLength();j++){
currentNode = nodeList.item(j);
System.out.println("Node name: "+currentNode.getNodeName());
System.out.println("Node value: "+currentNode.getTextContent());
}
}
}
}
you can simply use XStream library for xml parsing it will parse java object to xml and vice versa.
check out below link
http://x-stream.github.io/tutorial.html

xml node deletion not working properly in java using dom parser?

Here i have xml node where i'm displaying and selecting particular node to delete.For my below xml file and code ,only first node is deleting though i select second node.
<root>
<book> <!--node 1 -->
<id>1111</id>
<name>abacd</name>
<author>abcd</author>
<price>700</price>
<category>abcd</category>
</book>
<book> <!--node 2 -->
<id>2222</id>
<name>abacd</name>
<author>abcd</author>
<price>700</price>
<category>abcd</category>
</book>
<book> <!--node 3 -->
<id>3333</id>
<name>abacd</name>
<author>abcd</author>
<price>700</price>
<category>abcd</category>
</book>
</root>
and my java code to delete node as
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(fXmlFile);
int nodeValue = Integer.parseInt(nodeNumber);
//nodeValue is node number eg: 2;
NodeList bookList = doc.getElementsByTagName("book");
for (int i = 1; i <= bookList.getLength(); i++) {
if (i == nodeValue) {
Element rootElement = (Element) doc.getElementsByTagName("book").item(0);
Element idElement = (Element) doc.getElementsByTagName("id").item(0);
idElement.getParentNode().removeChild(idElement);
Element nameElement = (Element) doc.getElementsByTagName("name").item(0);
nameElement.getParentNode().removeChild(nameElement);
Element authorElement = (Element) doc.getElementsByTagName("author").item(0);
authorElement.getParentNode().removeChild(authorElement);
Element priceElement = (Element) doc.getElementsByTagName("price").item(0);
priceElement.getParentNode().removeChild(priceElement);
Element categoryElement = (Element) doc.getElementsByTagName("category").item(0);
categoryElement.getParentNode().removeChild(categoryElement);
rootElement.getParentNode().removeChild(rootElement);
doc.normalize();
}
}
could anybody guide me where to change my code.
You always call the first node by this
doc.getElementsByTagName("book").item(0);
Instead try to use
doc.getElementsByTagName("book").item(nodeValue);
Or use bookList.item(nodeValue) to access the node directly
if we want to delete node according to node number then below code helps.I got my answer by this
int nodeValue = Integer.parseInt(nodeNumber);
NodeList bookList = doc.getElementsByTagName("book");
Node nNode = bookList.item(nodeValue);
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) nNode;
eElement.getParentNode().removeChild(nNode);
}
It will delete selected node (eg:2).

Parse XML node by node and check for leaf node

I used XPath expression //*[count(./*) = 0] to find the leaf nodes in an XML. But instead of using the expression, I wanted to parse the XML, node by node and check if it is a leaf node or not. How can I accomplish this? My XML is a dynamic one.
Using the following java code you can parse the xml and use docEle.hasChildNodes() to check it a leaf node or not.
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document dom = db.parse("file.xml");
Element docEle = dom.getDocumentElement();
NodeList nl = docEle.getChildNodes();
if (nl != null && nl.getLength() > 0) {
for (int i = 0; i < nl.getLength(); i++) {
if (nl.item(i).getNodeType() == Node.ELEMENT_NODE) {
Element el = (Element) nl.item(i);
el.getTextContent().trim();
}
}
}
}

Java XML with namespace issue

I have this code:
org.w3c.dom.Document doc = docBuilder.parse(representation.getStream());
Element element = doc.getDocumentElement();
NodeList nodeList = element.getElementsByTagName("xnat:MRSession.scan.file");
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
// do something with the current element
my problem is with getElementsByTagName("xnat:MRSession.scan.file")
my xml looks like this:
<?xml version="1.0" encoding="UTF-8"?><xnat:MRSession "REMOVED DATA IGNORE">
<xnat:sharing>
<xnat:share label="23_MR1" project="BOGUS_GSU">
<!--hidden_fields[xnat_experimentData_share_id="1",sharing_share_xnat_experimentDa_id="xnat_E00001"]-->
</xnat:share>
</xnat:sharing>
<xnat:fields>
<xnat:field name="studyComments">
<!--hidden_fields[xnat_experimentData_field_id="1",fields_field_xnat_experimentDat_id="xnat_E00001"]-->S</xnat:field>
</xnat:fields>
<xnat:subject_ID>xnat_S00002</xnat:subject_ID>
<xnat:scanner manufacturer="GE MEDICAL SYSTEMS" model="GENESIS_SIGNA"/>
<xnat:prearchivePath>/home/ryan/xnat_data/prearchive/BOGUS_OUA/20120717_131900137/23_MR1</xnat:prearchivePath>
<xnat:scans>
<xnat:scan ID="1" UID="1.2.840.113654.2.45.2.108830" type="SAG LOCALIZER" xsi:type="xnat:mrScanData">
<!--hidden_fields[xnat_imageScanData_id="1"]-->
<xnat:image_session_ID>xnat_E00001</xnat:image_session_ID>
<xnat:quality>usable</xnat:quality>
<xnat:series_description>SAG LOCALIZER</xnat:series_description>
<xnat:scanner manufacturer="GE MEDICAL SYSTEMS" model="GENESIS_SIGNA"/>
<xnat:frames>29</xnat:frames>
<xnat:file URI="/home/ryan/xnat_data/archive/BOGUS_OUA/arc001/23_MR1/SCANS/1/DICOM/scan_1_catalog.xml" content="RAW" file_count="29" file_size="3968052" format="DICOM" label="DICOM" xsi:type="xnat:resourceCatalog">
So Basically I need to be able to iterate through all the xnat:MRSession/xnat:scan/xnat:file
elements and make some changes. Problem is
getElementsByTagName("xnat:MRSession.scan.file")
Is always null. Please help. Thanks
You could try the following using XPath:
Document document = // the parsed document
XPathFactory xPathFactory = XPathFactory.newInstance();
NodeList allFileNodes = xPathFactory.newXPath().evaluate("\\XNAT_NAMESPACE:file", document.getDocumentElement(), XPathConstants.NODESET);
Instead XNAT_NAMESPACE you would need to specify the exact namespace that is meant with the prefix "xnat" in your example.

How do I resolve two nodes which have the same name but under different parents?

<PublicRecords>
<USBankruptcies>
<USBanktruptcy>...<USBankruptcy>
<CourtId>...</CourtId>
<USBanktruptcy>...<USBankruptcy>
<CourtId>...</CourtId>
</USBankruptcies>
<USTaxLiens>
<USTaxLien>...<USTaxLien>
<CourtId>...</CourtId>
<USTaxLien>...<USTaxLien>
<CourtId>...</CourtId>
</USTaxLiens>
<USLegalItems>
<USLegalItem><USLegalItem>
<CourtId></CourtId>
<USLegalItem><USLegalItem>
<CourtId></CourtId>
</USLegalItems>
</PubicRecords>
I am using a combination of doc and xpath objects to extract the attributes and node contents.
NodeList bp = doc.getElementsByTagName("USBankruptcy");
NodeList nl = doc.getElementsByTagName("CourtId");
long itrBP;
for (itrBP = 0; itrBP < bp.getLength(); itrBP++ )
{
Element docElement = (Element) bp.item(itrBP);
Element courtElement = (Element) nl.item(itrBP);
NodeList df = docElement.getElementsByTagName("DateFiled");
if(df.getLength() > 0)
{
dateFiled = nullIfBlank(((Element)df.item(0)).getFirstChild().getTextContent());
dateFiled = df.format(dateFiled);
}
But, when I say get elements of tag name CourtID, it will get all the CourtIDs, not just the ones under USBankruptcy.
Is there any way to specify the parent?
I tried NodeList nl = doc.getElementsByTagName("USBankruptcies/CourtId");
It gave me a dom error on run time.
Rather than calling the getElementsByTagName("CourtId") method on the Document, call it on the child Element (in your case, the <USBankruptcies> element).
NodeList bankruptcyNodes = doc.getElementsByTagName("USBankruptcies");
Element bankruptcyElement = (Element) bankruptcyNodes.item(0);
NodeList bankruptcyCourtNodes = bankruptcyElement.getElementsByTagName("CourtId");
// etc...
Please find the code here:
DocumentBuilderFactory domFactory = DocumentBuilderFactory
.newInstance();
domFactory.setNamespaceAware(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse("test.xml");
XPath xpath = XPathFactory.newInstance().newXPath();
XPathExpression expr = xpath.compile("*//USBankruptcies/CourtId");
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i));
}

Categories

Resources