I have a question regarding list of elements in xml
I am trying to delete everything under and also the tags.
But when I debug my list of param I noticed my list looks like this :
text
element
text
element
text
element
text
element
But I want only the elements in the list and not the text so I can more easily delete the correct element.
How to do this?
This is my code :
public void deleteParameter(int row, int index) {
int objTypeIndex = index + 1;
File xml = new File(XMLEditorService.getXMLEditorService().getFile());
try {
XMLOutputter xmlOut = new XMLOutputter();
org.jdom2.Document doc = new SAXBuilder().build(xml);
Namespace ns = Namespace.getNamespace("http://www.xxx.com");
org.jdom2.Element rootNode = doc.getRootElement();
org.jdom2.Element typeContent = rootNode.getChildren().get(
objTypeIndex);
List<Element> list = typeContent.getChildren("param", ns);
if (list.size() > 0) {
Element element = list.get(row); //remove correct element
element.removeContent();
System.out.println("element removed: " + element.getName());
xmlOut.setFormat(Format.getPrettyFormat());
xmlOut.output(doc, new FileWriter(XMLEditorService
.getXMLEditorService().getFile()));
}
} catch (IOException io) {
System.out.println(io.getMessage());
} catch (JDOMException jdomex) {
System.out.println(jdomex.getMessage());
}
}
The list i am refering to is this line : List<Element> list = typeContent.getChildren("param", ns);
The method call: element.removeContent(); does not remove the Element from its parent, but instead it removes all content from the element (makes it empty).
You probably just want to do: element.detach(); instead.... which will remove the Element (and as a result all of its content too) from the document.
You could use a JDOM2 filter to get elements of a specific type.
Look at This example to see how to retrieve specific elements of the XML using Filters in JDOM2.
Related
I'm trying to append a tag to the roo of my xml file, however I'm getting an error on createElement :
if(hashValidationRulesAtt.get("mandatory").equals("true") && (elemValue==null||elemValue.equals(""))){
DOCUMENTS.appendChild(doc.createElement(statusKO));}
else{
DOCUMENTS.appendChild(doc.createElement(statusOK));
}. Any help
if(hashValidationRulesAtt.get("mandatory").equals("true") && (elemValue==null||elemValue.equals(""))){
DOCUMENTS.appendChild(doc.createElement(statusKO));}
else{
DOCUMENTS.appendChild(doc.createElement(statusOK));
}
You should append the root element to the document and then append the childelements of the root to the root element.
Here is a bit of an example
Document doc = docBuilder.newDocument();
Element rootElement = doc.createElement("Expenses");
doc.appendChild(rootElement);
for (String s : list)
{
Element element = doc.createElement(type);
element.appendChild(doc.createTextNode(s));
rootElement.appendChild(element);
}
I am attempting to begin writing a program which uses DOM4j with which I wish to parse a XML file, save it to some tables and finally allow the user to manipulate the data.
Unfortunately I am stuck on the most basic step, the parsing.
Here is the portion of my XML I am attempting to include:
<?xml version="1.0"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.054.001.04">
<BkToCstmrDbtCdtNtfctn>
<GrpHdr>
<MsgId>000022222</MsgId>
When I attempt to find the root of my XML it does return the root correctly as "Document". When I attempt to get the child node from Document it also correctly gives me "BkToCstmrDbtCdtNtfctn". The problem is that when I try to go any further and get the child nodes from "Bk" I can't. I get this in the console:
org.dom4j.tree.DefaultElement#2b05039f [Element: <BkToCstmrDbtCdtNtfctn uri: urn:iso:std:iso:20022:tech:xsd:camt.054.001.04 attributes: []/>]
Here is my code, I would appreciate any feedback. Ultimately I want to get the "MsgId" attribute back but in general I just want to figure how to parse deeper into the XML because in reality it probably has about 25 layers.
public static Document getDocument(final String xmlFileName){
Document document = null;
SAXReader reader = new SAXReader();
try{
document = reader.read(xmlFileName);
}
catch (DocumentException e)
{
e.printStackTrace();
}
return document;
}
public static void main(String args[]){
String xmlFileName = "C:\\Users\\jhamric\\Desktop\\Camt54.xml";
String xPath = "//Document";
Document document = getDocument(xmlFileName);
Element root = document.getRootElement();
List<Node> nodes = document.selectNodes(xPath);
for(Iterator i = root.elementIterator(); i.hasNext();){
Element element = (Element) i.next();
System.out.println(element);
}
for(Iterator i = root.elementIterator("BkToCstmrDbtCdtNtfctn");i.hasNext();){
Element bk = (Element) i.next();
System.out.println(bk);
}
}
}
The best approach is probably to use XPath, but since the XML document uses namespaces, you cannot use the "simple" selectNodes methods in the API. I would create a helper method to easily evaluate any XPath expression on either the Document or the Element level:
public static void main(String[] args) throws Exception {
Document doc = getDocument(...);
Map<String, String> namespaceContext = new HashMap<>();
namespaceContext.put("ns", "urn:iso:std:iso:20022:tech:xsd:camt.054.001.04");
// Select the first GrpHdr element in document order
Element element = (Element) select("//ns:GrpHdr[1]", doc, namespaceContext);
System.out.println(element.asXML());
// Select the text content of the MsgId element
Text msgId = (Text) select("./ns:MsgId/text()", element, namespaceContext);
System.out.println(msgId.getText());
}
static Object select(String expression, Branch contextNode, Map<String, String> namespaceContext) {
XPath xp = contextNode.createXPath(expression);
xp.setNamespaceURIs(namespaceContext);
return xp.evaluate(contextNode);
}
Note that the XPath expression must use namespace prefixes that is mapped to the namespace URIs used in the input document, but that the actual value of the prefix doesn't matter.
I am not able to remove an element from root element. Below is the example of xml
<ADMIN-DATA>
<DATA-DECLARATION ID="Hi"> </DATA-DECLARATION>
<DATA ID="Hi">
<DATA-DECLARATION-REF ID-REF="Hi"> </DATA-DECLARATION-REF>
<DATA ID="Hi">
<DATA-DECLARATION ID="Delete"> </DATA-DECLARATION>
</DATA>
</DATA>
</ADMIN-DATA>
I want to delete
<DATA-DECLARATION ID="Delete"> </DATA-DECLARATION>
JDOM Code below
Element root = document.getRootElement();
String id = null;
boolean check = false;
String idRef = null;
ElementFilter filter = new org.jdom2.filter.ElementFilter(
"DATA-DECLARATION");
ElementFilter filter2 = new org.jdom2.filter.ElementFilter(
"DATA-DECLARATION-REF");
for (Element dataDecId : root.getDescendants(filter))
{
check = false;
id = dataDecId.getAttributeValue("ID");
for (Element dataDecIdRef : root.getDescendants(filter2))
{
idRef = dataDecIdRef.getAttributeValue("ID-REF");
if (null != idRef && idRef.equalsIgnoreCase(id))
{
check = true;
break;
}
}
if (!check)
{
root.removeContent(dataDecId);
}
}
Above root.removeContent(dataDecId); is not working. Correct me.
Note that <DATA-DECLARATION ID="Delete"> </DATA-DECLARATION> is not a child of the root element.... it's a child of a DATA element which in turn is a child of a DATA element which finally is a child of the ADMIN-DATA element.
You cannot ask the root element to remove DATA-DECLARATION ID="Delete" because it is not a direct child.
Note that the child itself knows it's location, so, the simpler way to do it, is to change root.removeContent(dataDecId) to be just dataDecId.detach()
Well, to me it looks like there are some errors in the .xml file. You're trying to get the ID-REF field whereas Delete only has an ID.
Moreover, I doubt that your XML file is correct considering you have a typo here:
<DATA-DECLARATION-REF ID-REF="Hi"> </ATA-DECLARATION-REF>
and two different tags here:
<DATA-DECLARATION ID="Delete"> </DATA-DECLARATION-REF>.
Another way:
XPATH combines tag and values in a clear way:
XPath xPath = XPathFactory.newInstance().newXPath();
String expression="//DATA-DECLARATION[#ID='Delete']"; // self-explained
NodeList nodes = (NodeList) xPath.compile(expression).evaluate(document, XPathConstants.NODESET);
for(int i=0; i<nodes.getLength(); i++)
{
Node the_node = nodes.item(i);
if(the_node instanceof Element)
{
Element the_element=(Element) the_node;
// FATHER
Node father=the_node.getParentNode();
// SUPPRESSION
father.removeChild(the_node);
// First one only ?
break;
}
}
I have problem with updating data in my xml file.
My xml file looks like this :
<root>
<info>
.....
</info>
<OBJECT_TYPE>x2000</OBJECT_TYPE>
<prop>
<DESCRIPTION>fast train</DESCRIPTION>
<PARENT>NULL</PARENT>
<VIRTUAL>0</VIRTUAL>
<VISIBLE>1</VISIBLE>
<PICTURE>NULL</PICTURE>
<HELP>NULL</HELP>
<MIN_NO>1</MIN_NO>
<MAX_NO>1</MAX_NO>
<NAME_FORMAT>NULL</NAME_FORMAT>
</prop>
<param>
<PARAMETER>nidbrc</PARAMETER>
<DATA_TYPE>String</DATA_TYPE>
<DESCRIPTION>super fast</DESCRIPTION>
<MIN_NO>1</MIN_NO>
<MAX_NO>1</MAX_NO>
<ORDER1>1</ORDER1>
<NESTED>1</NESTED>
<DEFAULT1>NULL</DEFAULT1>
<FORMAT>100:45</FORMAT>
</param>
<param>
</param>
<param>
</param>
<param>
</param>
...
</type>
<type>
...
</type>
<type>
</root>
Here i am trying to get my first param from type number 1 and updating the first parameter of 9
public static void main(String[] args) {
File xml = new File("test.xml");
try {
XMLOutputter xmlOut = new XMLOutputter();
Document doc = (Document) new SAXBuilder().build(xml);
Element rootNode = doc.getRootElement();
Element typeContent = rootNode.getChildren().get(1);
System.out.println("typeContent : " + typeContent.getChildren());
for (int i = 0; i < typeContent.getContentSize(); i++) {
List<Element> list = typeContent.getChildren("param");
if (list.size() > 0) {
Element element = list.get(1);
List paramChilds = element.getChildren("PARAMETER");
for (int j = 0; j < paramChilds.size(); j++) {
Element node = (Element) paramChilds.get(j);
System.out.println(node.getText());
// xmlOut.setFormat(Format.getPrettyFormat());
// xmlOut.output(doc, new FileWriter("test.xml"));
}
}
}
} catch (IOException io) {
System.out.println(io.getMessage());
} catch (JDOMException jdomex) {
System.out.println(jdomex.getMessage());
}
What I find hard is to know how to dig into the xml file and therefore this one aint working but this one is null : node.getChild("PARAMETER").setText("Bla");
You could either loop all 'param' children like this:
Document doc = (Document) new SAXBuilder().build(xml);
Element rootNode = doc.getRootElement();
// get all 'param' children
List<Element> paramElements = root.getChildren("param");
for (Element param: paramElements) {
// do something intelligent
param.getChild("PARAMETER").setText("Bla");
}
// write to file
xmlOut.setFormat(Format.getPrettyFormat());
xmlOut.output(doc, new FileWriter("test.xml"));
Or you could use xpath to search for the elements and do stuff with it; example.
Here, you appear to be trying to set the text of the first PARAMETER element which is a child of the first PARAMETER element that is a child of the second child of the root element.
Element rootNode = doc.getRootElement();
...
Element typeContent = rootNode.getChildren().get(1);
...
Element node = typeContent.getChild("PARAMETER");
node.getChild("PARAMETER").setText("Bla");
No such element appears to exist in your example xml.
typeContent corresponds to the element <OBJECT_TYPE>x2000</OBJECT_TYPE>, which has no PARAMETER element children.
There are no PARAMETER elements that are children of
PARAMETER elements.
What's more, for some reason you seem to be doing exactly the same thing 15 times. Why is that?
You are looking for the param Elements like this:
List<Element> list = typeContent.getChildren("param");
But typeContent does not have any param children. typeContent is:
Element typeContent = rootNode.getChildren().get(1);
which, as far as I can tell, is:
<OBJECT_TYPE>x2000</OBJECT_TYPE>
You should, I guess, be looking for the param children like:
List<Element> paramElements = root.getChildren("param");
You should be using JDOM2 and not JDOM. With JDOM2 your XPath option is much simpler:
XPathExpression<Element> paramxpath = XPathFactory.instance()
.compile("/root/param", Filters.element());
for (Element param : paramxpath.evaluate(doc)) {
System.out.println(param.getText());
}
This is my complete solution :
public void updateParameters(int index, int row, int column,
String columnName, Object data) throws Exception {
int objTypeIndex = index + 1;
File xml = new File("xmlFiles/CoreDatamodel.xml");
try {
XMLOutputter xmlOut = new XMLOutputter();
org.jdom2.Document doc = new SAXBuilder().build(xml);
Namespace ns = Namespace.getNamespace("http://www.bombardier.com");
org.jdom2.Element rootNode = doc.getRootElement();
org.jdom2.Element typeContent = rootNode.getChildren().get(
objTypeIndex);
List<Element> list = typeContent.getChildren("param", ns);
if (list.size() > 0) {
Element element = list.get(row);
List paramChilds = element.getChildren(columnName, ns);
Element node = (Element) paramChilds.get(0);
node.setText(data.toString());
System.out.println(node.getText());
xmlOut.setFormat(Format.getPrettyFormat());
xmlOut.output(doc, new FileWriter("xmlFiles/CoreDatamodel.xml"));
}
} catch (IOException io) {
System.out.println(io.getMessage());
} catch (JDOMException jdomex) {
System.out.println(jdomex.getMessage());
}
}
Currently I have the code below to put the data in a Hash.
My question: which value do i have to put in the part of !!!SOMETHING!!!.
The code only has to read one elementtag and insert it's value in the hashtable.
public void ReadXML(){
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(fileout);
doc.getDocumentElement().normalize();
Hashtable hash = new Hashtable();
NodeList dataNodes = doc.getElementsByTagName("DataArea");
// getChildNodes().item(0).getChildNodes();
Element root = doc.getDocumentElement();
String dataNodeIndex = root.toString();
System.out.println("");
for (int dataNodeIndex1 = 0; dataNodeIndex1 < dataNodes.getLength(); dataNodeIndex1++)
{
Node nodeName = dataNodes.item(dataNodeIndex1);
if (nodeName.getNodeType() == Node.ELEMENT_NODE) {
Element elementName = (Element) nodeName;
NodeList elementNameList = elementName.getElementsByTagName(elementtag1);
Element elementName2 = (Element) elementNameList.item(0);
NodeList nameElement = elementName2.getChildNodes();
System.out.println("NodeContent: " + ((Node) nameElement.item(0)).getNodeValue());
}
hash.put(elementtag1, !!!SOMETHING!!!);
System.out.println(hash);
}
}
catch(Exception e){
e.printStackTrace();
}
}
You should use these method that i found :
protected String getString(String tagName, Element element) {
NodeList list = element.getElementsByTagName(tagName);
if (list != null && list.getLength() > 0) {
NodeList subList = list.item(0).getChildNodes();
if (subList != null && subList.getLength() > 0) {
return subList.item(0).getNodeValue();
}
}
return null;
}
use it like this :
if (NodeName.getNodeType() == Node.ELEMENT_NODE) {
Element ElementName = (Element) NodeName;
Hash.put(Elementtag1, getString(Elementtag1, ElementName));
}
Check it out :
http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/
and
How to retrieve element value of XML using Java?
You have chosen incorrect collection type for this operation, if you wanna save your element tag values in Set yes it is better to use HashSet but implementation of HashSet approximately you try to do, so values of Set puts into HashMap like keys, but you can use another collection like List, Queue, Stack try to find better for you.
And maybe SAX will be better DOM for you ...
To make things easier and more robust, you could use a Properties instead, which has an underlying implementation of a Hashtable (it actually extends it) and can import and export to/from XML (see loadFromXML and storeToXML methods). See http://www.ibm.com/developerworks/java/library/j-tiger02254/index.html for details.