How to display XML Object generated using JAXB UnMarshaller? - java

I'm using JAXB marshalling to create XML files, and it created successfully, and know i want to display these files using JAXB unMarshalling, here is the code i'm using:
public Object display(String fileName) throws IOException, JAXBException {
XmlStructure object;
File file = new File(fileName);
JAXBContext jaxbContext = JAXBContext.newInstance(XmlStructure.class);
Unmarshaller jaxbUnMarshaller = jaxbContext.createUnmarshaller();
object = (XmlStructure) jaxbUnMarshaller.unmarshal(file);
System.out.println(object.toString());
return object;
}
the previous code gives me that result:
com.nc.inotify.dp.xml.impl.XmlStructure#2916a6bf
and i changed the code with that:
public Object display(String fileName) throws IOException, JAXBException {
XmlStructure object;
File file = new File(fileName);
JAXBContext jaxbContext = JAXBContext.newInstance(XmlStructure.class);
Unmarshaller jaxbMarshaller = jaxbContext.createUnmarshaller();
object = (XmlStructure) jaxbMarshaller.unmarshal(file);
Marshaller jaxbMarshallerz = jaxbContext.createMarshaller();
jaxbMarshallerz.marshal(object, System.out);
return object;
}
but it gives me that result:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><XmlSource/>
and this is the XML file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<XmlSource>
<XmlConf>
<hostName>weather.yahooapis.com</hostName>
<parameters>
<entry>
<key>w</key>
<value>2502265</value>
</entry>
</parameters>
<URLPath>/forecastrss</URLPath>
<urlProtocol>http</urlProtocol>
</XmlConf>
<XmlConf>
<hostName>weather.yahooapis.com</hostName>
<parameters>
<entry>
<key>w</key>
<value>2553822</value>
</entry>
</parameters>
<URLPath>/forecastrss</URLPath>
<urlProtocol>http</urlProtocol>
</XmlConf>
</XmlSource>
Update
*NOTE*: i'm using more than one class in the marshaling process in order to get that form
The marshaling method:
public void add(String fileName) throws IOException, JAXBException,
ParserConfigurationException, SAXException, TransformerException {
this.fileName = fileName;
File temp = new File(tempName);
JAXBContext jaxbContext = JAXBContext.newInstance(XmlConfList.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
File source = new File(fileName);
if (source.exists()) {
jaxbMarshaller.marshal(object, temp);
MergeXml merge = new MergeXml();
merge.mergeXML(true, fileName, tempName, mainTag);
} else {
XmlStructure struct = new XmlStructure();
jaxbMarshaller.marshal(struct, source);
jaxbMarshaller.marshal(object, temp);
MergeXml merge = new MergeXml();
merge.mergeXML(true, fileName, tempName, mainTag);
}
temp.delete();
}
The MergeXml class:
public class MergeXml {
private static final String YES = "yes";
private static final String generalTag = "*";
/**
* This method used to merge XML old and new files together
*/
public void mergeXML(boolean condition, String fileName, String tempName, String mainTag)
throws ParserConfigurationException, SAXException, IOException,
TransformerException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = null;
Document doc = null;
Document doc2 = null;
db = dbf.newDocumentBuilder();
doc = db.parse(new File(fileName));
doc2 = db.parse(new File(tempName));
NodeList elements = doc.getElementsByTagName(mainTag);
if (condition == true) {
NodeList nodeList = doc2.getElementsByTagName(generalTag);
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
Node childNode = doc.adoptNode(node);
elements.item(0).appendChild(childNode);
}
}
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, YES);
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new StringWriter());
transformer.transform(source, result);
BufferedWriter output = new BufferedWriter(new FileWriter(fileName));
String xmlOutput = result.getWriter().toString();
output.write(xmlOutput);
output.close();
}
}
The XmlStructure class:
#XmlRootElement(name = "XmlSource")
public class XmlStructure{
}
The XmlConf class:
#XmlRootElement(name = "XmlConf")
public class XmlConf extends XmlStructure {
private String URLProtocol;
private List<String> path = new ArrayList<String>();
private String urlp;
private Map<String, String> parameters;
private String host;
/**
* This method used to retrieve the specified URL protocol
* #return {#code String}
*/
public String getUrlProtocol() {
return URLProtocol;
}
/**
* This method used to store the URL protocol as String if the URL is a valid one
* #param URL Protocol
*
*/
#XmlElement
public void setUrlProtocol(String URLProtocol) {
this.URLProtocol = URLProtocol;
}
/**
* This method used to retrieve all the paths selected
* by the user in order to save
* #return {#code List<String>}
*/
#XmlElement
public List<String> getPath() {
return path;
}
/**
* This method used to store a new path added by the user
* #param path
*
*/
public void setPath(String path) {
this.path.add(path);
}
/**
* This method used to set the path of the specified URL
* #param urlp
*
*/
#XmlElement(name = "URLPath")
public void setUrlPath(String urlp) {
this.urlp = urlp;
}
/**
* This method used to retrieve the path of the specified URL
* #return {#code String}
*/
public String getUrlPath() {
return urlp;
}
/**
* This method used to set the parameters of the specified URL
* #param parameters
*
*/
#XmlElementWrapper
public void setParameters(Map<String, String> parameters) {
this.parameters = parameters;
}
/**
* This method used to retrieve the parameters
* of the specified URL
* #return {#code Map<String, String>}
*/
public Map<String, String> getParameters() {
return parameters;
}
/**
* This method used to set the host name of the specified URL
* #param host
*
*/
public void setHostName(String host) {
this.host = host;
}
/**
* This method used to retrieve the host name of the
* specified URL
* #return {#code String}
*/
public String getHostName() {
return host;
}
}
The XmlConfList class:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class XmlConfList {
#XmlElementWrapper(name = "XmlSource")
#XmlElement(name = "XmlConf")
private List<XmlConf> list = null;
public List<XmlConf> getList() {
if(this.list == null)
this.list = new ArrayList<>();
return this.list;
}
}

Related

Facing some strange issue while bookmarking the paragraph

public class BookmarkAdd extends AbstractSample {
public static JAXBContext context = org.docx4j.jaxb.Context.jc;
/**
* #param args
*/
#SuppressWarnings("deprecation")
public static void main(String[] args) throws Exception {
String inputfilepath = "Chapter_3.docx";
File file = new java.io.File(inputfilepath);
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new java.io.File(inputfilepath));
MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();
String outputfilepath = System.getProperty("user.dir")+"/ 1.docx";
ClassFinder finder = new ClassFinder(P.class); // <----- change this to suit
new TraversalUtil(documentPart.getContent(), finder);
int Counter = 0;
System.out.println(finder.results.size());
for (Object o : finder.results)
{
P para =(P)o;
String name = "para" + Counter;
bookmarkPara(para, 0, para.getParagraphContent().size(), name, Counter);
Counter++;
SaveToZipFile saver = new SaveToZipFile(wordMLPackage);
saver.save(outputfilepath);
// wordMLPackage.save(new java.io.File(inputfilepath));
}
}
/**
* Surround the specified r in the specified p
* with a bookmark (with specified name and id)
* #param p
* #param r
* #param name
* #param id
*/
public static void bookmarkPara(P p, int StartIndex,int EndIndex, String name, int id) {
ObjectFactory factory = Context.getWmlObjectFactory();
BigInteger ID = BigInteger.valueOf(id);
// Add bookmark end first
CTMarkupRange mr = factory.createCTMarkupRange();
mr.setId(ID);
JAXBElement<CTMarkupRange> bmEnd = factory.createBodyBookmarkEnd(mr);
p.getParagraphContent().add(EndIndex, bmEnd); // from 2.7.0, use getContent()
// Next, bookmark start
CTBookmark bm = factory.createCTBookmark();
bm.setId(ID);
bm.setName(name);
JAXBElement<CTBookmark> bmStart = factory.createBodyBookmarkStart(bm);
p.getParagraphContent().add(StartIndex, bmStart);
}
public static List<Object> getAllElementFromObject(Object obj, Class<?> toSearch) {
List<Object> result = new ArrayList<Object>();
if (obj instanceof JAXBElement)
obj = ((JAXBElement<?>) obj).getValue();
if (obj.getClass().equals(toSearch))
result.add(obj);
else if (obj instanceof ContentAccessor) {
List<?> children = ((ContentAccessor) obj).getContent();
for (Object child : children) {
result.addAll(getAllElementFromObject(child, toSearch));
}
}
return result;
}
}
Using this code I bookmarks each paragraph as para0 to paran and this code works very fine for most of the document But I am not able to bookmark for two of my docx file I don't know why it shows the following error.
java.lang.IllegalArgumentException: obj parameter must not be null
at javax.xml.bind.helpers.AbstractMarshallerImpl.checkNotNull(Unknown Source)
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(Unknown Source)
at org.docx4j.openpackaging.parts.JaxbXmlPart.marshal(JaxbXmlPart.java:361)
at org.docx4j.openpackaging.parts.JaxbXmlPart.marshal(JaxbXmlPart.java:330)
at org.docx4j.openpackaging.io.SaveToZipFile.saveRawXmlPart(SaveToZipFile.java:249)
at org.docx4j.openpackaging.io.SaveToZipFile.saveRawXmlPart(SaveToZipFile.java:198)
at org.docx4j.openpackaging.io.SaveToZipFile.savePart(SaveToZipFile.java:424)
at org.docx4j.openpackaging.io.SaveToZipFile.addPartsFromRelationships(SaveToZipFile.java:387)
at org.docx4j.openpackaging.io.SaveToZipFile.savePart(SaveToZipFile.java:442)
at org.docx4j.openpackaging.io.SaveToZipFile.addPartsFromRelationships(SaveToZipFile.java:387)
at org.docx4j.openpackaging.io.SaveToZipFile.save(SaveToZipFile.java:168)
at org.docx4j.openpackaging.io.SaveToZipFile.save(SaveToZipFile.java:97)
at Backup.BookmarkAdd.main(BookmarkAdd.java:64)
.....

How to generate XML file from elements map?

I need to generate an XML file from just having a map, which contains the parent element and his children.
Map looks like this:
Map<String, List<Element>> elementMap = new LinkedHashMap<String, List<Element>>();
root: el1 el2 el3 el4 // root is the parent and el1... are his children.
el1: el5 el6
el2: el7 el8
Expected XML Model:
<root>
<el1>
<el5></el5>
<el6></el6>
</el1>
<el2>
<el7></el7>
<el8></el87>
</el2>
<el3></el3>
<el4></el4>
</root>
Can you give me some tips, algorithms how I could generate that XML?
I thought about recursion, but I don't know where to start.
Any suggestions?
Your thoughts were good.
You have to use iterating every one of your map keys and generate the list of elements based on values from this key. The result should be append to the general document.
You haven't posted your Element class. I will show some example based on Map<String, List<String>> elementMap.
Here is code snippet:
import com.epam.lab.model.exceptions.CreateDocumentConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class XmlBuilder {
private DocumentBuilder builder;
private Document doc;
/**
* Constructs an item list builder.
*
* #throws CreateDocumentConfigurationException
*/
public XmlBuilder() throws CreateDocumentConfigurationException {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
builder = factory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
throw new CreateDocumentConfigurationException("exception create new document", e);
}
}
/**
* Builds a DOM document for an array list of items.
*
* #param elementMap map of items.
* #return a DOM document describing the items.
*/
public Document build(Map<String, List<String>> elementMap) {
doc = builder.newDocument();
doc.appendChild(createItems(elementMap));
return doc;
}
/**
* Builds a DOM element for an array list of items.
*
* #param elementMap the map of items
* #return a DOM element describing the items
*/
private Element createItems(Map<String, List<String>> elementMap) {
Element e = null;
for (Map.Entry<String, List<String>> anItem : elementMap.entrySet()) {
e = doc.createElement(anItem.getKey());
for (Node node : createItemsList(anItem.getValue())) {
e.appendChild(node);
}
}
return e;
}
private List<Node> createItemsList(List<String> items) {
List<Node> result = new ArrayList<>();
for (String item : items) {
Element item1 = createItem(item);
result.add(item1);
}
return result;
}
/**
* Builds a DOM element for an item.
*
* #param anItem the item
* #return a DOM element describing the item
*/
private Element createItem(String anItem) {
// if you need some text element to your element - just append it here.
return doc.createElement(anItem);
}
/**
* Builds the text content for document
*
* #param name element
* #param text content
* #return text element
*/
private Element createTextElement(String name, String text) {
Text t = doc.createTextNode(text);
Element e = doc.createElement(name);
e.appendChild(t);
return e;
}
private String generateXmlContent(Map<String, List<String>> elementMap) {
String content;
Document doc = build(elementMap);
DOMImplementation impl = doc.getImplementation();
DOMImplementationLS implLS = (DOMImplementationLS) impl.getFeature("LS", "3.0");
LSSerializer ser = implLS.createLSSerializer();
ser.getDomConfig().setParameter("format-pretty-print", true);
content = ser.writeToString(doc);
return content;
}
public void writeToXmlFile(String xmlContent) {
File theDir = new File("./output");
if (!theDir.exists())
theDir.mkdir();
String fileName = "./output/" + this.getClass().getSimpleName() + "_"
+ Calendar.getInstance().getTimeInMillis() + ".xml";
try (OutputStream stream = new FileOutputStream(new File(fileName))) {
try (OutputStreamWriter out = new OutputStreamWriter(stream, StandardCharsets.UTF_16)) {
out.write(xmlContent);
out.write("\n");
}
} catch (IOException ex) {
System.err.println("Cannot write to file!" + ex.getMessage());
}
}
public static void main(String[] args) throws CreateDocumentConfigurationException {
XmlBuilder xmlBuilder = new XmlBuilder();
Map<String, List<String>> map = MapFactory.mapOf(MapFactory.entry("root", Arrays.asList("element1", "element2", "element3")));
String xmlContent = xmlBuilder.generateXmlContent(map);
xmlBuilder.writeToXmlFile(xmlContent);
}
}
After generating XML document you have to write it to file.
But you have to prepare XML content before writing, something like:
private String generateXmlContent(Map<String, List<String>> elementMap) {
String content;
Document doc = build(elementMap);
DOMImplementation impl = doc.getImplementation();
DOMImplementationLS implLS = (DOMImplementationLS) impl.getFeature("LS", "3.0");
LSSerializer ser = implLS.createLSSerializer();
ser.getDomConfig().setParameter("format-pretty-print", true);
content = ser.writeToString(doc);
return content;
}
And finally writing to file can look like:
public void writeToXmlFile(String xmlContent) {
File theDir = new File("./output");
if (!theDir.exists())
theDir.mkdir();
String fileName = "./output/" + this.getClass().getSimpleName() + "_"
+ Calendar.getInstance().getTimeInMillis() + ".xml";
try (OutputStream stream = new FileOutputStream(new File(fileName))) {
try (OutputStreamWriter out = new OutputStreamWriter(stream, StandardCharsets.UTF_16)) {
out.write(xmlContent);
out.write("\n");
}
} catch (IOException ex) {
System.err.println("Cannot write to file!", ex);
}
}
Utility factory for creating Map, based on literals:
public class MapFactory {
// Creates a map from a list of entries
#SafeVarargs
public static <K, V> Map<K, V> mapOf(Map.Entry<K, V>... entries) {
LinkedHashMap<K, V> map = new LinkedHashMap<>();
for (Map.Entry<K, V> entry : entries) {
map.put(entry.getKey(), entry.getValue());
}
return map;
}
// Creates a map entry
public static <K, V> Map.Entry<K, V> entry(K key, V value) {
return new AbstractMap.SimpleEntry<>(key, value);
}
}
After executing main() I have got following XML file XmlBuilder_1456910256665.xml:
<?xml version="1.0" encoding="UTF-16"?>
<root>
<element1/>
<element2/>
<element3/>
</root>
You can use below fuction for converting the Map to an XML string.
public static String maptoXML(Object hashMap) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
XMLEncoder xmlEncoder = new XMLEncoder(bos);
xmlEncoder.writeObject(hashMap);
xmlEncoder.close();
return bos.toString();
}
Ref:http://pritomkumar.blogspot.in/2014/05/convert-map-hashmap-or-listarraylist-to.html?m=1

How to append to xml table with java?

Okay so I'm creating a users class which asks for input then stores it in an XML file using java. I figured out to create the original XML file I think but I'm have trouble figuring out how to add a new user with the attribute "id" of one more then the previous User entry.
Here is the code I have so far:
/*imports */
public class CreateUser {
static Scanner input = new Scanner(System.in);
/* object names*/
String name;
String age;
String bday;
String gender;
String location;
String orientation;
String relationship;
String hobbies;
String choice;
String username;
String password;
public void makeUser(){
/*left out code to get user entries here
seemed irrelevant/*
/*checks for file if it doesn't exist then it creates it else it should append
the user to the xml document with a id increase of one.
The appending part I'm not sure how to do.*/
File f = new File("C:\\Users\\Steven\\Workspace\\twitter\\src\\users.xml");
if(f.exists()) {
try {
/* need help here*/
}
}
else{
try{
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document users = docBuilder.newDocument();
Element user = users.createElement("user");
users.appendChild(user);
Attr attr = users.createAttribute("id");
attr.setValue("0");
user.setAttributeNode(attr);
Element dname = users.createElement("name");
dname.appendChild(users.createTextNode(name));
user.appendChild(dname);
Element dgender = users.createElement("gender");
dgender.appendChild(users.createTextNode(gender));
user.appendChild(dgender);
Element dlocation = users.createElement("location");
dlocation.appendChild(users.createTextNode(location);
user.appendChild(dlocation);
Element dorientation = users.createElement("orientation");
dorientation.appendChild(users.createTextNode(orientation));
user.appendChild(dorientation);
Element drelationship = users.createElement("relationship");
drelationship.appendChild(users.createTextNode(relationship));
drelationship.appendChild(drelationship);
Element dhobbies = users.createElement("hobbies");
dhobbies.appendChild(users.createTextNode(hobbies));
dhobbies.appendChild(dhobbies);
Element dchoice = users.createElement("choice");
dchoice.appendChild(users.createTextNode(choice));
dchoice.appendChild(dchoice);
Element dusername = users.createElement("username");
dusername.appendChild(users.createTextNode(username));
dusername.appendChild(dusername);
Element dpassword = users.createElement("password");
dpassword.appendChild(users.createTextNode(password));
dpassword.appendChild(dpassword);
Element dbday = users.createElement("birthday");
dbday.appendChild(users.createTextNode(bday));
dbday.appendChild(dbday);
Element dage = users.createElement("age");
dage.appendChild(users.createTextNode(age));
dage.appendChild(dage);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(users);
StreamResult result = new StreamResult(new File("C:\\Users\\Steven\\Workspace\\twitter\\src\\users.xml"));
StreamResult test = new StreamResult(System.out);
transformer.transform(source, result);
} catch (ParserConfigurationException pce) {
pce.printStackTrace();
} catch (TransformerException tfe) {
tfe.printStackTrace();
}
}
}
I know its a lot of code to look through and I don't want an exact coded answer but maybe just how to append the user with the attribute value one more then the previous entry. Or a point in a the direction of a helpful website. Anything really I've been perplexed for a little and I feel like I should get something this simple. Thanks in advance for any help
In your first section(if block), I think you can open your file in append mode as below to add an user, assuming user node is not wrapped in another node.
StreamResult result = new StreamResult(
new FileWriter("C:\\Users\\Steven\\Workspace\\twitter\\src\\users.xml", true));
There are two changes in above statement:
Using FileWriter in place of File
Using a second parameter true, which open the file in append mode.
EDIT: To get the max existing ID, you need to read file and look for ID tag as below:
File xmlFile = new File("C:\\Users\\Steven\\Workspace\\twitter\\src\\users.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(xmlFile);
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName("userId");//use the id tag name
int maxId = 0;
for(Node node: nList){
if(Integer.parseInt(node.getTextContent()) > maxId ){
maxId = Integer.parseInt(node.getTextContent());
}
}
int newId = maxId +1; //use this ID
xmlFile.close();//close the file
Consider JAXB, here is a working example to start with:
static class Users {
private List<User> user = new ArrayList<>();
public List<User> getUsers() {
return user;
}
public void setUsers(List<User> users) {
this.user = users;
}
}
static class User {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public static void main(String[] args) throws Exception {
User user = new User();
user.setName("user1");
Users users = new Users();
users.setUsers(Arrays.asList(user));
JAXB.marshal(users, new File("users.xml"));
users = JAXB.unmarshal(new File("users.xml"), Users.class);
User user2 = new User();
user2.setName("user2");
users.getUsers().add(user2);
JAXB.marshal(users, System.out);
}
Consider SAX, unlike DOM it's fast and has no size limit. Here's a basic example:
public static void main(String[] args) throws Exception {
String xml = "<users><user><name>user1</name></user></users>";
XMLReader xr = new XMLFilterImpl(XMLReaderFactory.createXMLReader()) {
#Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equals("users")) {
addUser();
}
super.endElement(uri, localName, qName);
}
private void addUser() throws SAXException {
super.startElement("", "", "user", null);
addFileld("name", "user2");
super.endElement("", "", "user");
}
private void addFileld(String name, String value) throws SAXException {
super.startElement("", "", name, null);
super.characters(value.toCharArray(), 0, value.length());
super.endElement("", "", name);
}
};
Source src = new SAXSource(xr, new InputSource(new StringReader(xml)));
Result res = new StreamResult(System.out);
TransformerFactory.newInstance().newTransformer().transform(src, res);
}
output:
<users><user><name>user1</name></user><user><name>user2</name></user></users>

Simple XML parse XML to List

I use Simple XML (simple-xml-2.6.2.jar) to parse xml file like:
<?xml version="1.0" encoding="UTF-8" ?>
<orderList>
<order id="1">
<name>NAME1</name>
</order>
<order id="2">
<name>NAME2</name>
</order>
</orderList>
The root Element contains subElements.
I wanna it be ArrayList, How to do it?
Here's a possible solution, hope it helps you:
Annotations of Order class:
#Root(name="order")
public class Order
{
#Attribute(name="id", required=true)
private int id;
#Element(name="name", required=true)
private String name;
public Order(int id, String name)
{
this.id = id;
this.name = name;
}
public Order() { }
// Getter / Setter
}
Example class, containing the list:
#Root(name="elementList")
public class Example
{
#ElementList(required=true, inline=true)
private List<Order> list = new ArrayList<>();
// ...
}
And here's some code for reading your code:
Serializer ser = new Persister();
Example example = ser.read(Example.class, file); // file = your xml file
// 'list' now contains all your Orders
List is an interface, ArrayList is one of its implementation, like:
List<Order> l = new ArrayList<Order>()
So if you have a List , you basically have what you want.
If I've interpreted your question correctly, you want a list of orders. I've not tested this for your setup but this works for me for a similar xml structure (assumes you have a custom class called Order):
List<Order> orders = new ArrayList<Order>();
XMLDOMParser parser = new XMLDOMParser();
AssetManager manager = context.getAssets();
InputStream stream;
try {
stream = manager.open("test.xml"); //need full path to your file here - mine is stored in assets folder
Document doc = parser.getDocument(stream);
}catch(IOException ex){
System.out.printf("Error reading xml file %s\n", ex.getMessage());
}
NodeList nodeList = doc.getElementsByTagName("order");
for (int i = 0; i < nodeList.getLength(); i++) {
Element e = (Element) nodeList.item(i); //each order item
Node order=nodeList.item(i);
subList = order.getFirstChild(); //get the name child node
orders.add(order);
}
//XMLDOMParser Class
public class XMLDOMParser {
//Returns the entire XML document
public Document getDocument(InputStream inputStream) {
Document document = null;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder db = factory.newDocumentBuilder();
InputSource inputSource = new InputSource(inputStream);
document = db.parse(inputSource);
} catch (ParserConfigurationException e) {
Log.e("Error: ", e.getMessage());
return null;
} catch (SAXException e) {
Log.e("Error: ", e.getMessage());
return null;
} catch (IOException e) {
Log.e("Error: ", e.getMessage());
return null;
}
return document;
}
/*
* I take a XML element and the tag name, look for the tag and get
* the text content i.e for <employee><name>Kumar</name></employee>
* XML snippet if the Element points to employee node and tagName
* is name I will return Kumar. Calls the private method
* getTextNodeValue(node) which returns the text value, say in our
* example Kumar. */
public String getValue(Element item, String name) {
NodeList nodes = item.getElementsByTagName(name);
return this.getTextNodeValue(nodes.item(0));
}
private final String getTextNodeValue(Node node) {
Node child;
if (node != null) {
if (node.hasChildNodes()) {
child = node.getFirstChild();
while(child != null) {
if (child.getNodeType() == Node.TEXT_NODE) {
return child.getNodeValue();
}
child = child.getNextSibling();
}
}
}
return "";
}
}

Insert new element to an XML file using SAX Filter

I have an XMl file that looks like:
<?xml version="1.0" encoding="UTF-8"?>
<game >
<moves>
<turn>2</turn>
<piece nr="1" />
<turn>4</turn>
<piece nr="1" />
</moves>
</game>
I am writing a Java program that takes the XML file as input then parses it with SAX and SAX filter and computes:
the sum of the content of turn element (here=6)
the number of piece elements (here=2)
Then I want to use a SAX filter in order to generate an output XML file that are the same as the input one but with an additional element like:
<s:statistics>
<s:turn-total>6</s:turn-total>
<s:piece-count>2</s:piece-count>
</s:statistics>
The prefix s is a reference to a namespace.
My program so far is:
public class test{
public static void main(String[] args) throws Exception {
if (args.length != 2) {
System.err.println("error ");
System.exit(1);
}
String xmlInput = args[0];
String filteredXML = args[1];
test test1 = new test();
test1.sax(xmlInput, filteredXML);
}
private void sax(String gameXML, String filteredGameXML)throws Exception{
FileInputStream fis = new FileInputStream( gameXML);
InputSource is = new InputSource(fis);
XMLReader xr = XMLReaderFactory.createXMLReader();
XMLFilter xf = new MyFilter();
xf.setParent(xr);
xr = xf;
xr.parse(is);
xr.setFeature("http://xml.org/sax/features/namespaces", true);
DefaultHandler handler = new DefaultHandler();
xr.setContentHandler(handler);
}
private class MyFilter extends XMLFilterImpl{
StringBuffer buffer;
int temp=0;
int sum=0;
String ff;
int numof=0;
private MyFilter() {}
#Override
public void startDocument() throws SAXException {
System.out.println( "START DOCUMENT" );
numof=0;
}
public void startElement(String namespaceURI, String localName, String name, Attributes attributes) throws SAXException{
if(localName.equals("turn")){
buffer=new StringBuffer();
}
if("piece".equals(name)){
numof++;
}
}
public void characters(char[] ch, int start, int length) throws SAXException {
String s=new String(ch, start, length);
if(buffer!=null){
buffer.append(s);
}
}
public void endElement(String uri, String localName, String name)throws SAXException {
if(buffer!=null ){
ff=buffer.toString();
temp=Integer.valueOf(ff);
sum=sum+temp;
}
buffer=null;
}
public void endDocument() throws SAXException {
System.out.println( "END DOCUMENT" );
System.out.println("sum of turn: "+ sum);
System.out.println("sum of piece: "+ numof);
}
}
}
What should I do next?
Your XMLFilter should delegate to another ContentHandler that serializes the document based on the sax events.
SAXTransformerFactory factory = (SAXTransformerFactory)TransformerFactory.newInstance();
TransformerHandler serializer = factory.newTransformerHandler();
Result result = new StreamResult(...);
serializer.setResult(result);
XMLFilterImpl filter = new MyFilter();
filter.setContentHandler(serializer);
XMLReader xmlreader = XMLReaderFactory.createXMLReader();
xmlreader.setFeature("http://xml.org/sax/features/namespaces", true);
xmlreader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
xmlreader.setContentHandler(filter);
xmlreader.parse(new InputSource(...));
Your callback should delegate to the super implementation, which forwards the events to the serializing ContentHandler.
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
super.startElement(namespaceURI, localName, qName, atts);
...
}
In your endElement callback you can check if your are at the final closing tag and add additional sax events.
public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
super.endElement(namespaceURI, localName, qName);
if ("game".equals(localName)) {
super.startElement("", "statistics", "statistics", new AttributesImpl());
char[] chars = String.valueOf(num).toCharArray();
super.characters(chars, 0, chars.length);
super.endElement("", "statistics", "statistics");
}
...
}
Correct me if i'm wrong but i think XMLReader and XMLFilter are not really supposed to change a document. I can provide a different approach which with you can change the content of your document too:
public class ExtXMLConfig {
private JAXBContext context;
private Marshaller m;
private Unmarshaller um;
private Schema schema = null;
/**
* Creates an ExtXMLConfig-object, which uses rootClass as object to parse
* and save XML-files.
*
* #param rootClass
* the class use create/parse xml-files from
* #throws JAXBException
*/
public ExtXMLConfig(Class<?> rootClass) throws JAXBException {
context = JAXBContext.newInstance(rootClass);
init();
}
/**
* Creates an ExtXMLConfig, which uses a classPath like javax.xml.bin to use
* all classes in that path to parse and write xml-files
*
* #param classPath
* the class path containing all needed java-objects
* #throws JAXBException
*/
public ExtXMLConfig(String classPath) throws JAXBException {
context = JAXBContext.newInstance(classPath);
init();
}
/**
* Parses a xml-file into a JavaObject.
*
* #param file
* path to the xml-file
* #return a java-Object
*/
public Object load(String file) {
return load(new File(file));
}
/**
* Parses a xml-file into a JavaObject.
*
* #param xml
* File-object representing the xml-file
* #return a java-Object
*/
public Object load(File xml) {
um.setSchema(schema);
if (xml.exists() && xml.isFile()) {
try {
return um.unmarshal(xml);
} catch (JAXBException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
System.out.println("Failed to open file: " + xml.getAbsolutePath());
}
return null;
}
/**
* Saves a object into a xml-file.
*
* #param xml
* the object to save
* #param file
* path to the file to save to
*/
public void save(Object xml, String file) {
save(xml, new File(file));
}
/**
* Saves a object into a xml-file.
*
* #param xml
* the object to save
* #param file
* File-object representing the file to save to
*/
public void save(Object xml, File file) {
if (xml != null) {
m.setSchema(schema);
if (!file.isDirectory()) {
try {
if (!file.exists()) {
file.createNewFile();
}
m.marshal(xml, file);
} catch (JAXBException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/**
* Returns a formatted string representation of a xml-file given as a
* java-Object.
*
* #param xml
* the java-object to parse the xml from.
* #return a formatted string representation of the given object
*/
public String toString(Object xml) {
StringWriter out = new StringWriter();
try {
m.setSchema(schema);
m.marshal(xml, out);
return out.toString();
} catch (JAXBException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
private void init() throws JAXBException {
m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
um = context.createUnmarshaller();
}
Using this class to parse your xml-Files you would only need a Class like this:
#XmlRootElement // used to parse this class as xml-Root
public class Game {
private Move moves;
public Game() {};
public void setMove(Move moves) {
this.moves = moves;
}
public Moves getMoves() {
return this.moves;
}
}
with Move being an instance of another class which has the fields you need and also has a annotation for XmlRootElement.
I hope this helps.
Using #Jorn Horstmann's (http://stackoverflow.com/users/139595/jorn-horstmann) answer from above you can easily add the missing elements. But to write the results to an XML file you should use the TransformerHandler.
Just create a very basic ContentHandler and use it instead of the DefaultHandler. In the ContentHandler you can implement all the basic functions (startDocument, startElement etc.) and add every element to a new Transformer.
e.g.
In your startDocument function:
Transformer t = hd.getTransformer();
t.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
t.setOutputProperty(OutputKeys.METHOD, "xml");
t.setOutputProperty(OutputKeys.INDENT, "yes");
hd.startDocument();
And then (in each other function) add this:
e.g. for startElement:
hd.startElement(uri,localName,name,attributes);
Finally you can write all this to a file in the endDocument method.

Categories

Resources