Copy certain nodes with Java - java

I'm trying to read/copy a certain part of a xml document in JAVA and then save this part as a new xml document. So like in de example below you see studentinfo and contact info, I just want to select studentinfo and copy the entire area so nodes and elements.
I can only find info about selecting only the element or only the nodes.
So help would be appreciated, thank you.
<header>
<body>
<studentinfo>
<name>Student Name<name>
<studentid>0987654321<studentid>
<Location>USA<Location>
<studentinfo>
<contactinfo>
<email>email#email.com<email>
<address>somewhere 1<address>
<postalcode>123456<postalcode>
<contactinfo>
<body>
<header>

I'm going to make a big assumption, and that is that you are using the org.w3c.dom.Document api.
This is a two step process:
Document doc = parse(xmlSource);
Document targetDoc = openTargetDoc();
Node copyTo = findWhereYouWantToCopyStuffTo(targetDoc);
// Find the node or nodes to want to copy.. could use XPath or some other search
NodeList studentinfoList = doc.getElementsByTagName("studentinfo");
// for each found... make a copy (via importNode) and attach to some point in the target doc
for( int i = 0; i < studnetinfoList.getLength(); i ++ ){
Node n = studentinfoList.item(i);
Node copyOfn = targetDoc.importNode(n,true);
copyTo.appendChild(copyOfn);
}
If this isn't what you are looking for, you might need to add a bit more detail of what you wish to copy and where to, using what api etc.

Related

Copying attributes from one XML element to another with Java

I am writing a Java program that will create an XML file from various pieces of data.
There are attribute strings containing URLs that are reused throughout the XML. I wanted to reuse these attributes (i.e., copy them from one element to another). I currently have something like this:
public class copyAttributes {
public static final String google_url = "http://www.google.com";
DocumentBuilderFactor docFac = DocumentBuilderFactory.newInstance();
DocumentBuilder build = docFactory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
public static Attr googleAttr = doc.createAttribute("ref:GoogleMainSite");
googleAttr.setValue(google_url);
Element rootElement = doc.createElement("Root_Element");
rootElement.setAttributeNode(googleAttr);
...this is fine so far if I don't have any other elements.
Now, I want to have multiple elements containing that same Google URL attribute node. I know that's redundant, but I'm following an XSD that specifically says attributes have to be reused. I know you can't just do this:
Element childElement = doc.createElement("Child_Element");
childElement.setAttributeNode(googleAttr);
rootElement.appendChild(childElement);
...because I know you will get an INUSE_ATTRIBUTE_ERR (I tried, that's how I know). But I want to reuse this attribute, as it will occur many times throughout the XML.
I did find this: sample code for copying attributes from one element to another, but when I included that sample "Utils" class in my package and called it this way:
Utils utils = new Utils();
utils.copyAttributes(rootElement, childElement);
...I receive a "NAMESPACE_ERR: An attempt is made to create or change an object in a way which is incorrect with regard to namespaces."
There isn't much information out there about this "Namespace_err" message.
The other solution I found is to simply clone an element. But this doesn't solve my problem either, since in some cases I won't want to reuse all of the attributes of another element, I will only want to use a couple of them.
Basically my question is: How do you go about reusing attribute nodes on multiple elements in an XML schema created via a Java program?
you can try this:
public void copyAttributes(Element from, Element to)
{
NamedNodeMap attributes = from.getAttributes();
for (int i = 0; i < attributes.getLength(); i++)
{
Attr node = (Attr) attributes.item(i);
to.setAttributeNode((Attr) node.cloneNode(false));
}
}

Uknown XML file into pojo

Is there any way to take an unknown schema xml file and convert the values, tags, etc from the xml file into pojo? I looked at jaxb and it seems like the best way to use that is if you already know the xml schema. So basically, I want to be able to parse the tags from the xml put each into its own object maybe through the use of an arraylist. Did I just not fully understand what jaxb can or is there a better tool that can do this, or is it just too hard to implement?
In the hope that this helps you to understand your situation!
public static void dumpAllNodes( String path ) throws Exception {
DocumentBuilder parser =
DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = parser.parse(new File(path));
NodeList nodes = doc.getElementsByTagNameNS( "*", "*" );
for( int i = 0; i < nodes.getLength(); i++ ){
Node node = nodes.item( i );
System.out.println( node.getNodeType() + " " + node.getNodeName() );
}
}
The NodeList nodes contains all element nodes, in document order (opening tag). Thus, elements contained within elements will be in that list, all alike. To obtain the attributes of a node, call
NamedNodeMap map = node.getAttributes();
The text content of a node is available by
String text = node.getTextContent();
but be aware that calling this returns the text in all elements of a subtree.
OTOH, you may call
Element root = doc.getDocumentElement();
to obtain the root element and then descend the tree recursively by calling Element.getChildNodes() and process the nodes (Element, Attr, Text,...) one by one. Also, note that Node.getParentNode() returns the parent node, so you could construct the XPath for each node even from the flat list by repeating this call to the root.
It simply depends what you expect from the resulting data structure (what you call ArrayList). If, for instance, you create a generic element type (MyElement) containing one map for attributes and another one for child elements, the second map would have to be
Map<String,List<MyElement>> name2elements
to provide for repeated elements - which makes access to elements occurring only once a little awkward.
I hope that I have illustrated the problems of generic XML parsing, which is not a task where JAXB can help you.

How to scrape strings inside given tags?

I have a XML read into a one single String. I need to get all the data inside <code> tags. I do not need to go though whole XML file parsing them. Can i use a simple string processing technique to get the data inside those tags.
input : <a><b><code>Hello</code></b><code>World</code></a>
output : Hello, World
Regex is not an advisable tool to play with XML, specially when there are sophiticated many parsers are there. You may use javax.xml.xpath package to do this stuff for you like:
XPath xp = XPathFactory.newInstance().newXPath();
NodeList nl = (NodeList)xp.evaluate("//code", new InputSource(new StringReader("<a><b><code>Hello</code></b><code>World</code></a>")), XPathConstants.NODESET);
for(int i=0; i< nl.getLength(); i++){
System.out.print(nl.item(i).getTextContent()+", ");
}
will result
Hello, World,
Follow the example here: it's simple.

How to append element in a XML file using dom?

My XML file looks like this:
<Messages>
<Contact Name="Robin" Number="8775454554">
<Message Date="24 Jan 2012" Time="04:04">this is report1</Message>
</Contact>
<Contact Name="Tobin" Number="546456456">
<Message Date="24 Jan 2012" Time="04:04">this is report2</Message>
</Contact>
<Messages>
I need to check whether the 'Number' attribute of Contact element is equal to 'somenumber' and if it is, I'm required to insert one more Message element inside Contact element.
How can it be achieved using DOM? And what are the drawbacks of using DOM?
The main drawback to using a DOM is it's necessary to load the whole model into memory at once, rather than if your simply parsing the document, you can limit the data you keep in memory at one point. This of course isn't really an issue until your processing very large XML documents.
As for the processing side of things, something like the following should work:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document dom = db.parse(is);
NodeList contacts = dom.getElementsByTagName("Contact");
for(int i = 0; i < contacts.getLength(); i++) {
Element contact = (Element) contacts.item(i);
String contactNumber = contact.getAttribute("Number");
if(contactNumber.equals(somenumber)) {
Element newMessage = dom.createElement("Message");
// Configure the message element
contact.appendChild(newMessage);
}
}
DOM has two main disadvantages:
It requires reading of the complete XML into a Java representation in memory. That can be both time and memory consuming
It is a pretty verbose API, so you need to write a lot of code to achieve simple things like you're asking for.
If time and memory consumption is OK for you, but verbosity is not, you could still use jOOX, a library that I have created to wrap standard Java DOM objects to simplify manipulation of XML. These are some examples of how you would implement your requirement with jOOX:
// With css-style selectors
String result1 = $(file).find("Contact[Number=somenumber]").append(
$("<Message Date=\"25 Jan 2012\" Time=\"23:44\">this is report2</Message>")
).toString();
// With XPath
String result2 = $(file).find("//Contact[#Number = somenumber]").append(
$("<Message Date=\"25 Jan 2012\" Time=\"23:44\">this is report2</Message>")
).toString();
// Instead of file, you can also provide your source XML in various other forms
Note that jOOX only wraps standard Java DOM. The underlying operations (find() and append(), as well as $() actually perform various DOM operations).
You will do something to this effect.
Get the NodeList of Contact element.
Iterate through the NodeList and get Contact element.
Get Number through contact.getAttribute("Number") where contact is of type Element.
If your number equals someNumber, then add Message by calling contact.appendChild(). Message must be an element.
Use the Element class to create a new element
Element message = doc.createElement("Message");
message.setAttribute("message", strMessage);
Now add this element after whatever element you want using
elem.getParentNode().insertBefore(message, elem.getNextSibling());
You might want to take a look at this tutorial its about exactly what you want to do

how to get Node & node values from XML in java

I have an xml trying to parse & read it, but dont know how many nodes the xml may contain? So I am trying to read the node & node values ?
How I get the same say:
<company>
<personNam>John</personName>
<emailId>abc#test.com</emaiId>
<department>Products</department>
(may have additionaly nodes & values for same)
</company>
Sorry forgot to add my code, using Dom:-
Document document = getDocumentBuilder().parse(new ByteArrayInputStream(myXML.getBytes("UTF-8")));
String xPathExp = "//company";
XPath xPath = getXPath();
NodeList nodeList = (NodeList)xPath.evaluate(xPathExp, document, XPathConstants.NODESET);
nodeListSize = nodeList.getLength();
System.out.println("#####nodeListSize"+nodeListSize);
for(int i=0;i<nodeListSize;i++){
element=(Element)nodeList.item(i);
m1XMLOutputResponse=element.getTextContent();
System.out.println("#####"+element.getTagName()+" "+element.getTextContent());
}
Consider using the JAXB library. It's really a painless way of mapping your XML to Java classes and back. The basic principle is that JAXB takes your XML Schemas (XSD) and generates corresponding Java classes for you. Then you just call marshall or unmarshall methods which populate your Java class with the contents of the XML, or generates the XML from your Java class.
The only drawback is, of course, that you'd need to know how to write the XML Schemas :)
Learn how to use XML DOM. Here is an example on how to use XML DOM to fetch node and node values.

Categories