org.integratedmodelling.utils.xml.XMLDocument Maven / Gradle / Ivy
The newest version!
/*******************************************************************************
* Copyright (C) 2007, 2014:
*
* - Ferdinando Villa
* - integratedmodelling.org
* - any other authors listed in @author annotations
*
* All rights reserved. This file is part of the k.LAB software suite,
* meant to enable modular, collaborative, integrated
* development of interoperable data and model components. For
* details, see http://integratedmodelling.org.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the Affero General Public License
* Version 3 or any later version.
*
* This program is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* merchantability or fitness for a particular purpose. See the
* Affero General Public License for more details.
*
* You should have received a copy of the Affero General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* The license is also available at: https://www.gnu.org/licenses/agpl.html
*******************************************************************************/
package org.integratedmodelling.utils.xml;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.xerces.parsers.DOMParser;
import org.integratedmodelling.collections.Pair;
import org.integratedmodelling.exceptions.KlabException;
import org.integratedmodelling.exceptions.KlabIOException;
import org.integratedmodelling.exceptions.KlabRuntimeException;
import org.integratedmodelling.exceptions.KlabValidationException;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ProcessingInstruction;
import org.xml.sax.InputSource;
/**
* Trivial helper class to wrap the read/write interface for an XML file without having to remember too much.
* Non-ADD people need not apply.
*
* Write operations will fail if the document has been read from a non-writable source (a
* write protected file or a remote URL).
*
* @author Ferdinando Villa
*/
public class XMLDocument {
DOMParser parser;
Document dom;
String namespace = null;
boolean isWritable = false;
boolean needsWrite = false;
File docFile = null;
Element root = null;
public class NodeIterator implements Iterator {
Node _current = null;
public NodeIterator(Node node) {
_current = node.getFirstChild();
}
@Override
public boolean hasNext() {
return _current != null;
}
@Override
public Node next() {
Node ret = _current;
_current = _current.getNextSibling();
if (ret == null)
System.out.println("FUCK I'M RETURNING A FUCKING NULL");
return ret;
}
@Override
public void remove() {
throw new KlabRuntimeException("Node iterator is read only");
}
}
public NodeIterator iterator() {
return new NodeIterator(root());
}
public NodeIterator iterator(Node node) {
return new NodeIterator(node);
}
public XMLDocument(String rootNode) throws KlabValidationException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = null;
try {
docBuilder = factory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
throw new KlabValidationException(e);
}
dom = docBuilder.newDocument();
root = dom.createElement(rootNode);
dom.appendChild(root);
}
public XMLDocument(File f) throws KlabIOException {
createFromFile(f, null);
}
public XMLDocument(URL f) throws KlabIOException {
createFromUrl(f);
}
public XMLDocument(File f, String namespace) throws KlabIOException {
createFromFile(f, namespace);
}
public Node createNode(String tag, Node parent) {
Node ret = null;
ret = dom.createElement(tag);
parent.appendChild(ret);
return ret;
}
public void addNamespace(String ns, String uri) {
// if (uri.endsWith("#")) {
// uri = uri.substring(0, uri.length()-1);
// }
Attr ret = dom.createAttributeNS(uri, ns);
root.setAttributeNode(ret);
}
public void addAttribute(Node parent, String aName, String aValue) {
if (parent instanceof Element) {
Attr ret = dom.createAttribute(aName);
ret.setValue(aValue);
((Element) parent).setAttributeNode(ret);
}
}
private void createFromUrl(URL url) throws KlabIOException {
// if (!NetUtilities.urlResponds(url.toString())) {
// throw new ThinklabIOException(e);
// }
InputStream is = null;
try {
is = url.openStream();
} catch (IOException e) {
throw new KlabIOException(e);
}
createFromInputStream(is);
try {
is.close();
} catch (IOException e) {
throw new KlabIOException(e);
}
}
private void createFromInputStream(InputStream is) throws KlabIOException {
parser = new DOMParser();
try {
parser.setFeature("http://xml.org/sax/features/namespaces", true);
parser.parse(new InputSource(is));
} catch (Exception e) {
throw new KlabIOException(e);
}
dom = parser.getDocument();
}
private void createFromFile(File f, String namespace) throws KlabIOException {
this.namespace = namespace;
this.docFile = f;
if (!f.exists()) {
/* create XML document */
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(namespace != null);
try {
dom = factory.newDocumentBuilder().newDocument();
} catch (ParserConfigurationException e) {
/* why in the world should this happen? */
}
isWritable = new File(f.getParent()).canWrite();
} else {
isWritable = f.canWrite();
FileInputStream is;
try {
is = new FileInputStream(f);
} catch (FileNotFoundException e) {
throw new KlabIOException(e);
}
createFromInputStream(is);
try {
is.close();
} catch (IOException e) {
throw new KlabIOException(e);
}
}
}
@Override
protected void finalize() throws KlabIOException {
if (needsWrite)
flush();
}
public XMLDocument(InputStream is) throws KlabException {
parser = new DOMParser();
try {
parser.setFeature("http://xml.org/sax/features/namespaces", true);
parser.parse(new InputSource(is));
} catch (Exception e) {
throw new KlabValidationException(e);
}
dom = parser.getDocument();
}
public Element root() {
return root == null ? dom.getDocumentElement() : root;
}
public void flush() throws KlabIOException {
Transformer transformer = null;
try {
transformer = TransformerFactory.newInstance().newTransformer();
} catch (Exception e) {
throw new KlabIOException(e);
}
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StreamResult result = new StreamResult(docFile);
DOMSource source = new DOMSource(dom);
try {
transformer.transform(source, result);
} catch (TransformerException e) {
throw new KlabIOException(e);
}
}
/**
* Take a xml element and the tag name, look for the tag and get
* the text content
* i.e for John xml snippet if
* the Element points to employee node and tagName is name I will return John
* @param ele
* @param tagName
* @return the string value.
*/
public static String getTextValue(Element ele, String tagName) {
String textVal = null;
NodeList nl = ele.getElementsByTagName(tagName);
if (nl != null && nl.getLength() > 0) {
Element el = (Element) nl.item(0);
textVal = el.getFirstChild().getNodeValue();
}
return textVal;
}
public static String getTextValue(Element ele, String tagName, String optionalPrefix) {
String ret = getTextValue(ele, tagName);
if (ret == null) {
ret = getTextValue(ele, optionalPrefix + ":" + tagName);
}
return ret;
}
public static String getNodeValue(Node node) {
StringBuffer buf = new StringBuffer();
NodeList children = node.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node textChild = children.item(i);
if (textChild.getNodeType() != Node.TEXT_NODE
&& textChild.getNodeType() != Node.CDATA_SECTION_NODE) {
continue;
}
buf.append(textChild.getNodeValue());
}
return buf.toString();
}
/**
* Calls getTextValue and returns a int value
* @param ele
* @param tagName
* @return the int value
*/
public static int getIntValue(Element ele, String tagName) {
// in production application you would catch the exception
return Integer.parseInt(getTextValue(ele, tagName));
}
/**
* Extract attribute string value from node.
* @param n the Node
* @param attr the attribute name
* @return attribute value, or null if not there.
*/
public static String getAttributeValue(Node n, String attr) {
String ret = null;
if (n.hasAttributes()) {
Node nn = n.getAttributes().getNamedItem(attr);
if (nn != null)
ret = nn.getTextContent();
}
return ret;
}
/**
* Return the given attribute value or the given default parameter if not there.
* @param n
* @param attr
* @param defval
* @return attribute value
*/
public static String getAttributeValue(Node n, String attr, String defval) {
String ret = getAttributeValue(n, attr);
return ret == null ? defval : ret;
}
public static Node getChildNode(Node nn, String string) {
Node ret = null;
for (Node n = nn.getFirstChild(); n != null; n = n.getNextSibling())
if (n.getNodeName().equals(string)) {
ret = n;
break;
}
return ret;
}
public static Node findNode(Node node, String string) {
Node ret = null;
String name = node.getNodeName();
if (name != null && name.equals(string))
return node;
for (Node n = node.getFirstChild(); n != null; n = n.getNextSibling())
if ((ret = findNode(n, string)) != null) {
return ret;
}
return null;
}
public Node findNode(String s) {
return findNode(root(), s);
}
public Node findNode(String s, String optionalPrefix) {
Node ret = findNode(root(), s);
if (ret == null) {
ret = findNode(root(), optionalPrefix + ":" + s);
}
return ret;
}
public Collection getProcessingInstructions() {
ArrayList ret = new ArrayList();
for (Node n = dom.getFirstChild(); n != null; n = n.getNextSibling())
if (n.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) {
ret.add((ProcessingInstruction) n);
}
return ret;
}
public Node appendTextNode(String tag, String text, Node parent) {
Node nn = createNode(tag, parent);
nn.setTextContent(text);
return nn;
}
public void addProcessingInstruction(String target, String data) {
dom.createProcessingInstruction(target, data);
}
/**
* What this does should be obvious. How it does it is quite far from that.
*
* FIXME by now I just hard-coded options such as pretty printing. Of course we
* want to pass or set them.
*
* @param outfile
* @throws KlabIOException
*/
public void writeToFile(File outfile) throws KlabIOException {
Transformer transformer;
try {
transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(dom);
transformer.transform(source, result);
String xmlString = result.getWriter().toString();
OutputStream outputStream = new FileOutputStream(outfile);
outputStream.write(xmlString.getBytes());
outputStream.close();
} catch (Exception e) {
throw new KlabIOException(e);
}
}
/**
* What this does should be obvious. How it does it is quite far from that.
*
* FIXME by now I just hard-coded options such as pretty printing. Of course we
* want to pass or set them.
*
* @param outputStream
* @throws KlabIOException
*/
public void dump(OutputStream outputStream) throws KlabIOException {
Transformer transformer;
try {
transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(dom);
transformer.transform(source, result);
String xmlString = result.getWriter().toString();
outputStream.write(xmlString.getBytes());
} catch (Exception e) {
throw new KlabIOException(e);
}
}
public static Collection> getNodeAttributes(Node n) {
ArrayList> ret = new ArrayList>();
if (n.hasAttributes()) {
NamedNodeMap nnn = n.getAttributes();
for (int i = 0; i < nnn.getLength(); i++) {
Node zit = nnn.item(i);
ret.add(new Pair(zit.getNodeName(), zit.getTextContent()));
}
}
return ret;
}
}