/*
* This file is part of Caliph & Emir.
*
* Caliph & Emir is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Caliph & Emir 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
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Caliph & Emir; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Copyright statement:
* --------------------
* (c) 2005 by Werner Klieber (werner@klieber.info)
* http://caliph-emir.sourceforge.net
*/
package at.wklieber.tools;
import at.wklieber.Settings;
import org.jdom.*;
import org.jdom.input.SAXBuilder;
import org.jdom.output.DOMOutputter;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.jdom.xpath.XPath;
import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.logging.Logger;
public class XmlTools {
static Logger cat = Logger.getLogger(XmlTools.class.getName());
private static Console console = Console.getReference();
private static Settings cfg = Settings.getReference();
static final String XML_PATH_SEPARATOR = "/\\,. ;";
public XmlTools() {
}
/**
* This method parses the location-String and walks through the JDOM tree until
* the right child-Element is reached and returns this Element. If create is
* false, the default value is returned if a child doesn't exist. If create is
* true, non existing children are created.
* Note: if namespace is not null, the namespace is added to each new created element
* Note: support for attributes is not implemented
* Note: if there are more than one tag with the same name on a
* level, the one retrieved from getChild() is used (the first one).
* Note: high level methods for simpleXpath is in XmlTemplate class
*/
public static org.jdom.Element simpleXpath(org.jdom.Element rootElement1, String location1,
org.jdom.Element default1, boolean create1) {
return simpleXpath(rootElement1, location1, null, default1, create1);
}
public static org.jdom.Element simpleXpath(org.jdom.Element rootElement1, String location1,
Namespace nameSpace, org.jdom.Element default1, boolean create1) {
org.jdom.Element returnValue = default1;
try {
//System.out.println("go for: " + location1);
if ((location1 == null) || (location1.length() == 0) || (rootElement1 == null)) {
return returnValue;
}
String location = location1.trim();
StringTokenizer tokens = new StringTokenizer(location, XML_PATH_SEPARATOR, false);
// walk down the xml-hierachy
Element baseElement = rootElement1;
boolean isRootElement = true;
while (tokens.hasMoreTokens()) {
String token = tokens.nextToken();
if (baseElement == null) ;
Element newBase;
if (isRootElement) {
newBase = baseElement;
isRootElement = false;
} else {
if (nameSpace == null) {
newBase = baseElement.getChild(token);
} else {
newBase = baseElement.getChild(token, nameSpace);
}
}
if (newBase == null) { // this child doesn't exist
if (create1) {
if (nameSpace == null) {
newBase = new Element(token);
} else {
newBase = new Element(token, nameSpace);
}
baseElement.addContent(newBase);
//console.echo("Name: " + newBase.getName() + ", ns pre: <" + newBase.getNamespace().getPrefix() + ">, url: <" + newBase.getNamespace().getURI() + ">");
//console.echo(XmlTools.documentToString(rootElement1));
} else {
return returnValue;
}
} // end if baseElement
baseElement = newBase;
} // end while
returnValue = baseElement;
} catch (Exception e) {
cat.severe(e.toString());
}
return returnValue;
} // end method
// same as obove, just with Document instead of Element
public static org.jdom.Element simpleXpath(org.jdom.Document document1, String location1,
org.jdom.Element default1, boolean create1) {
org.jdom.Element returnValue = default1;
if ((location1 == null) || (location1.length() == 0) || (document1 == null)) {
return returnValue;
}
return simpleXpath(document1.getRootElement(), location1, returnValue, create1);
} // end method
public static String documentToString(Document doc) {
String ret = "";
if (doc != null) {
try {
XMLOutputter xml_out = new XMLOutputter(Format.getPrettyFormat());
StringWriter out = new StringWriter();
xml_out.output(doc, out);
ret = out.toString();
} catch (Exception e) {
e.printStackTrace();
}
}
return ret;
}
public static String documentToString(org.jdom.Element elem) {
String ret = "";
if (elem != null) {
org.jdom.Element elem2 = (org.jdom.Element) elem.clone(); // we need an Element with no parent
Document doc = new Document(elem2);
ret = documentToString(doc);
}
return ret;
}
public static Document stringToDocument(String strDoc1, boolean doValidate1) {
return stringToDocument(strDoc1, doValidate1, null);
}
public static Document stringToDocument(String strDoc1, boolean doValidate1, Document defaultValue1) {
Document returnValue = defaultValue1;
if (strDoc1 == null) {
return returnValue;
}
try {
Document temp = null;
SAXBuilder builder = new SAXBuilder();
/*
File f = File.createTempFile("xml", null);
FileTools.saveToFile(f.getAbsolutePath(), strDoc1);
File in = new File(f.getAbsolutePath());
*/
StringReader strIn = new StringReader(strDoc1);
builder.setValidation(doValidate1);
temp = builder.build(strIn);
if (temp != null) {
returnValue = temp;
}
} catch (Exception e) {
cat.severe(e.toString());
}
return returnValue;
}
public static Document fileToDocument(String fileName1, boolean doValidate1) {
Document ret = null;
if (fileName1 == null) {
cat.severe("Filename is NULL");
return ret;
}
String filename = FileTools.resolvePath(fileName1);
cat.fine("loading file" + filename);
if (!FileTools.existsFile(filename)) {
cat.severe("File \"" + filename + "\" doesn't exist");
return ret;
}
Document temp = null;
try {
SAXBuilder builder = new SAXBuilder();
File inFile = new File(filename);
builder.setValidation(doValidate1);
if (!doValidate1) {
builder.setDTDHandler(null);
}
temp = builder.build(inFile);
} catch (JDOMException je) {
cat.severe(je.toString());
} catch (Exception e) {
cat.severe(e.toString());
}
ret = temp;
return ret;
}
// this method replaces the content of "target" with the content of "source".
// this means everything: children, texts, ...
// not tested with attributes
public static void replaceElement(org.jdom.Element target, org.jdom.Element source) {
//target.removeChildren();
target.getChildren().clear();
//List new_copy = source.getChildren();
//Element new_copy = (Element) source.clone(); // without parent
List children = source.getChildren();
Iterator it = children.iterator();
Vector newList = new Vector();
while (it.hasNext()) {
// get child without parent
org.jdom.Element child = (org.jdom.Element) it.next();
newList.add(child.clone());
}
//target.setChildren(newList);
target.addContent(newList);
}
// convert a JDOM - document to a W3C-Element
public static org.w3c.dom.Document jdom2w3c(Document jdomElement1, org.w3c.dom.Document default1) {
org.w3c.dom.Document returnValue = default1;
try {
DOMOutputter outputter = new DOMOutputter();
returnValue = outputter.output(jdomElement1);
} catch (Exception e) {
cat.severe(e.toString());
}
return returnValue;
}
// convert a JDOM - Element to a W3C-Element
public static org.w3c.dom.Element jdom2w3c(Document jdomElement1, org.w3c.dom.Element default1) {
org.w3c.dom.Element returnValue = default1;
try {
DOMOutputter outputter = new DOMOutputter();
//returnValue = outputter.output(jdomElement1.getRootElement());
org.w3c.dom.Document d = outputter.output(jdomElement1);
returnValue = d.getDocumentElement();
//org.w3c.dom.Document resultDocument = outputter.output(jdomElement1);
//returnValue = Document.
} catch (Exception e) {
cat.severe(e.toString());
}
return returnValue;
}
/**
* Reads the file "fileName" and converts it to a JDOM-Document.
* If anything fails the input-default Document "doc" is returned
*/
public static Document readFromFile(String fileName, Document doc) {
Document returnValue = null;
try {
SAXBuilder builder = new SAXBuilder();
//File file = new File(new URI(fileName));
cat.fine("READ: " + fileName);
//File file = new File(FileTools.removeFileUrlPrefix(fileName));
returnValue = builder.build(new URL(FileTools.setUrlPrefix(fileName)));
} catch (Exception je) {
console.error("ERROR while reading file \"" + fileName + "\"");
je.printStackTrace();
returnValue = doc;
}
return returnValue;
}
/**
* Reads the file "fileName" and converts it to a e3c Element.
* If anything fails the input-default Element "default1" is returned
*/
public static org.w3c.dom.Element readFromFileW3c(String fileName1, org.w3c.dom.Element default1) {
org.w3c.dom.Element returnValue = default1;
Document doc = readFromFile(fileName1, null);
if (doc != null) {
returnValue = jdom2w3c(doc, returnValue);
}
return returnValue;
}
/**
* Reads the file "fileName" and converts it to a w3c document.
* If anything fails the input-default Document "default1" is returned
*/
public static org.w3c.dom.Document readFromFileW3c(String fileName1, org.w3c.dom.Document default1) {
org.w3c.dom.Document returnValue = default1;
Document doc = fileToDocument(fileName1, false);
if (doc != null) {
returnValue = jdom2w3c(doc, returnValue);
}
return returnValue;
}
// writes a JDOM document to a file in UFT
public static void saveToFile(String fname, Document doc) {
try {
XMLOutputter xml_out = new XMLOutputter(Format.getPrettyFormat());
String data = null;
if (doc != null) {
StringWriter out = new StringWriter();
xml_out.output(doc, out);
data = out.toString();
}
if (data == null)
data = "";
cat.fine("write string in utf8 to: " + fname);
FileTools.saveToFileUtf8(fname, data);
} catch (Exception e) {
e.printStackTrace();
}
} // end method
// validate an xml-String against an given dtd
public static boolean isDocumentValid(String strDoc1, String dtdFile) {
boolean ret = false;
cat.fine("Input-XML-String: " + strDoc1);
if (!FileTools.existsFile(dtdFile)) {
cat.severe("File \"" + dtdFile + "\" not found. Unable to validate");
return ret;
}
Document docOrginal = stringToDocument(strDoc1, false);
if (docOrginal == null) {
cat.severe("XML-String is not a valid XML-syntax");
return ret;
}
try {
//org.jdom.Element getRootElement;
//getRootElement = docOrginal.getRootElement();
String rootElement = docOrginal.getRootElement().getName();
rootElement = rootElement.trim();
cat.fine("Root-Element: <" + rootElement + ">");
String fileName = FileTools.resolvePath(dtdFile);
URL url = FileTools.getFileURL(fileName, null);
if (url == null) {
fileName = "";
} else {
fileName = url.toExternalForm();
}
DocType docType = new DocType(rootElement, fileName);
docOrginal.setDocType(docType);
String strDocDtd = documentToString(docOrginal);
cat.fine("strdocdtd: " + strDocDtd);
Document docDtd = stringToDocument(strDocDtd, true);
if (docDtd == null)
return ret;
ret = true;
} catch (Exception e) {
e.printStackTrace();
}
return ret;
}
// make a String, that represents the jaxb-tree
/*public static String jaxbSerialize(MarshallableRootElement element1) {
String ret = ConvertValues.buildErrorResponse("unable to generate xml-stream");
try {
OutputStream os = new ByteArrayOutputStream();
element1.validate();
element1.marshal(os);
ret = os.toString();
os.close();
} catch (Exception e) {
console.exitOnException(e);
}
return ret;
}
*/
/* // sava jaxb-tree to a xml-file
public static void jaxbSaveToFile(String filename1, MarshallableRootElement element1) {
try {
OutputStream os = new FileOutputStream(filename1);
element1.validate();
element1.marshal(os);
os.close();
} catch (Exception e) {
console.exitOnException(e);
}
} // end method*/
// lazy comparision. removes all #10,#13, tabs and spaces from the Strings
// and compares them.
// problem: the order of attributes may differ => method returns false
/*public static boolean compareXml(String xml1, String xml2) {
String in1 = xml1;
String in2 = xml2;
char[] ascChar = new char[1];
ascChar[0] = 9;
String asc_09 = new String(ascChar);
ascChar[0] = 10;
String asc_10 = new String(ascChar);
ascChar[0] = 13;
String asc_13 = new String(ascChar);
in1 = StringTools.replace(in1, asc_10, "");
in2 = StringTools.replace(in2, asc_10, "");
in1 = StringTools.replace(in1, asc_13, "");
in2 = StringTools.replace(in2, asc_13, "");
in1 = StringTools.replace(in1, asc_09, "");
in2 = StringTools.replace(in2, asc_09, "");
in1 = StringTools.replace(in1, " ", "");
in2 = StringTools.replace(in2, " ", "");
//cat.fine("str1: \"" + in1 + "\"");
//cat.fine("str2: \"" + in2 + "\"");
FileTools.saveToFile(cfg.getTestOutputDir() + "in1.txt", in1);
FileTools.saveToFile(cfg.getTestOutputDir() + "in2.txt", in2);
//return in1.equals(in2);
return in1.length() == in2.length();
}*/
// input String is a xpath query and the document to search
// output is a list of all matching Elements
public static List<Element> xpathQuery(org.jdom.Document document, String xpathQuery1, Namespace xNs) {
List<Element> returnValue = new ArrayList<Element>();
String xpathQuery = xpathQuery1;
XPath xPath;
try {
if (document == null || document.getRootElement() == null) {
return returnValue; //------------- EXIT POINT -------------
}
// if there is a xmlns namespace wihtout a prefix, then
// a default one has to be added. Otherwise jaxen does not work
// Note: the prefix "x" has to be used in the xpath-query as well.
Namespace ns = document.getRootElement().getNamespace();
if (ns.getPrefix().length() == 0) {
/*
StringTokenizer tokens = new StringTokenizer(xpathQuery, "/", true);
xpathQuery = "";
while (tokens.hasMoreTokens()) {
String token = tokens.nextToken();
if (!token.equalsIgnoreCase("/")) {
token = "x:" + token;
}
xpathQuery += token;
}*/
//xPath = new JDOMXPath(xpathQuery);
xPath = XPath.newInstance(xpathQuery);
//xPath.addNamespace(ns);
String uri = ns.getURI();
if (uri == null || uri.length() == 0) {
uri = "dummy";
}
//System.out.println("uir: \"" + uri + "\"");
//xPath.addNamespace("x", uri);
} else {
//xPath = new JDOMXPath(xpathQuery);
xPath = XPath.newInstance(xpathQuery);
xPath.addNamespace(ns);
}
if (xNs != null) {
xPath.addNamespace(xNs.getPrefix(), xNs.getURI());
}
//cat.fine("OLD: \"" + xpathQuery1 + "\", NEW: \"" + xpathQuery + "\"");
Object jdomNode = document; // Document, Element etc.
//XPath path = new JDOMXPath("/*"); //--> das root element
returnValue = xPath.selectNodes(jdomNode); // entries are from the type "org.jdom.Element"
} catch (Throwable e) {
e.printStackTrace();
}
return returnValue;
}
public static List<Element> xpathQuery(org.jdom.Document document, String xpathQuery1) {
return xpathQuery(document, xpathQuery1, null);
}
/**
* attention: the parent of the element is detached when no cloning
*
* @param aElement
* @param xpathQuery
* @param doClone
* @return
*/
public static List<Element> xpathQuery(org.jdom.Element aElement, String xpathQuery, boolean doClone) {
List<Element> returnValue = new ArrayList<Element>();
try {
//Document parentDocument;
//parentDocument = aElement.getDocument();
Document document;
Document oldDocument = null;
if (doClone) {
Element clone = (Element) aElement.clone();
document = new Document(clone);
} else {
oldDocument = aElement.getDocument();
aElement.detach();
document = new Document(aElement);
}
returnValue = xpathQuery(document, xpathQuery);
} catch (Exception e) {
cat.severe(e.toString());
}
return returnValue;
}
// just some test stuff for the jaxen xpath library
/*
public static void testJaxen() {
try {
org.jdom.Element root = new org.jdom.Element("root");
org.jdom.Element child = new org.jdom.Element("child");
child.setText("Ich bin ein Child");
root.addContent(child);
//org.jdom.Document doc1 = new org.jdom.Document(root);
org.jdom.Document doc = XmlTools.readFromFile(Settings.getConfigFile(), null);
org.jdom.Element e = doc.getRootElement();
Object jdomNode = e; // Document, Element etc.
*/
//XPath path = new JDOMXPath("/*"); //--> das root element
//XPath path = new JDOMXPath("/imbConfig/mmdbConnection/*/host");
/*
List results = path.selectNodes(jdomNode);
System.out.println("Test: \"" + documentToString(e) + "\"");
System.out.println("Results: " + results.size());
Iterator it = results.iterator();
while (it.hasNext()) {
org.jdom.Element elem = (org.jdom.Element) it.next();
System.out.println(elem.getName() + ", " + elem.getText());
}
} catch (Exception e) {
e.printStackTrace();
}
}
*/
public void xml2Pdf(org.jdom.Document document, OutputStream out) {
/*Templates template;
TransformerFactory tFactory = TransformerFactory.newInstance();
XMLFilter xmlFilter = ((SAXTransformerFactory) tFactory).newXMLFilter(template);
xmlFilter.setParent(XMLReaderFactory.createXMLReader());
Driver driver = new Driver();
driver.setRenderer(driver.RENDER_PDF);
driver.setOutputStream(out);
driver.render(xmlFilter, (new JDOMSource(document)).getInputSource());
driver.reset();*/
}
private static void goRecursive(Element startElement, String namespaceName, Namespace nameSpace, Namespace newNamespace) {
startElement.removeNamespaceDeclaration(nameSpace);
startElement.setNamespace(newNamespace);
List aList = startElement.getAttributes();
for (int i = 0; i < aList.size(); i++) {
Attribute a = (Attribute) aList.get(i);
//System.out.println("N: " + a.getName());
//if (a.getName().equalsIgnoreCase("type")) {
// System.out.println("NN: " + a.getName());
//}
String prefix = namespaceName + ":";
String value = a.getValue();
if (value.startsWith(prefix)) {
a.setValue(value.substring(prefix.length()));
}
}
List childList = startElement.getChildren();
for (int i = 0; i < childList.size(); i++) {
org.jdom.Element element = (org.jdom.Element) childList.get(i);
goRecursive(element, namespaceName, nameSpace, newNamespace);
}
}
/**
* Remove all tag element prefixes, eg. "<mpeg7:Mpeg7>" -> "<Mpeg7>"
*
* @param doc
*/
public static void removeAllNamespacesRecursive(org.jdom.Element doc) {
if (doc == null) {
return;
}
doc.setNamespace(null);
/*
console.echo("Prefix: \"" + namespace.getPrefix() + "\", URI: \"" + namespace.getURI() +
"\", toString: \"" + namespace.toString() + "\"");
console.echo("additional:");
for (int i = 0; i < docList.size(); i++) {
namespace = (Namespace) docList.get(i);
console.echo("Prefix: \"" + namespace.getPrefix() + "\", URI: \"" + namespace.getURI() +
"\", toString: \"" + namespace.toString() + "\"");
}
*/
List childList = doc.getChildren();
for (int i = 0; i < childList.size(); i++) {
org.jdom.Element element = (org.jdom.Element) childList.get(i);
removeAllNamespacesRecursive(element);
}
}
/**
* Remove all tag element prefixes, eg. "<mpeg7:Mpeg7>" -> "<Mpeg7>"
*
* @param doc
*/
public static void removeAllNamespacePrefix(org.jdom.Element doc) {
if (doc == null) {
return;
}
//Element rootElement = doc.getRootElement();
org.jdom.Element rootElement = doc;
String prefix = rootElement.getNamespacePrefix();
if (prefix == null || prefix.length() < 1) {
return;
}
//Namespace mpeg7Namespace = Mpeg7Template.getMpeg7Namespace();
//Namespace mpeg7Mpeg7Namespace = Namespace.getNamespace("mpeg7", "urn:mpeg:mpeg7:schema:2001");
Namespace newNameSpace = Namespace.getNamespace("", "urn:mpeg:mpeg7:schema:2001");
Namespace namespace = Namespace.getNamespace(prefix);
goRecursive(rootElement, prefix, namespace, newNameSpace);
}
/**
* detaches the node from the docuemnt and make a new document from it
*
* @param node
* @return
*/
public static Document getNewDocumentFromElement(Element node) {
Content c = node.detach();
java.util.List l = new ArrayList();
l.add(c);
Document d = new Document(l);
return d;
}
/**
* returns the text of the element the xpath points to. if the element does not exist, defaultValue is returned
*
* @param element the base element. e.g. new Element("root").add(..);
* @param xPath e.g. "root/person/firstname"
* @param defaultValue "no first name given"
* @return
*/
public static String getXmlText(Element element, String xPath, String defaultValue) {
String returnValue = defaultValue;
try {
Element elem = simpleXpath(element, xPath, null, false);
if (elem != null && elem.getText() != null) {
returnValue = elem.getText();
}
} catch (Exception e) {
e.printStackTrace();
}
return returnValue;
}
public static Document readFromFile(InputStream stream, Document defaultDocument) {
Document returnValue = null;
try {
SAXBuilder builder = new SAXBuilder();
//File file = new File(new URI(fileName));
cat.fine("READ: " + stream);
//File file = new File(FileTools.removeFileUrlPrefix(fileName));
returnValue = builder.build(stream);
} catch (Exception je) {
console.error("ERROR while reading stream \"" + stream + "\"");
je.printStackTrace();
returnValue = defaultDocument;
}
return returnValue;
}
} // end class