package org.alleypress.util.xml; import org.apache.xpath.XPathAPI; import org.w3c.dom.Document; import org.w3c.dom.DocumentType; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; import org.xml.sax.SAXException; import java.io.*; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Iterator; import java.util.Map; import java.util.Properties; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; /** * * XMLUtil was born from the need to print org.w3c.dom.Document objects and has * expanded to include automatic conversions from a java.sql.ResultSet to a * Document object. It will also parse a String and return a Document object. * For bugs or additions, send me an email.at croftontom@yahoo.com *
*
* Typical use can be as follows:
*
* ResultSet rs=con.createStatement.executeQuery("select name,address,phone from users");
* Document d=XMLUtil.resultSetToDoc(rs);
* //show what we got
* System.out.println(XMLUtil.docToString(d));
* //do some XSL processing
* * @author Tom Crofton * @version 1.9 * @email croftontom@yahoo.com * @created Nov 15, 2002 * @last modified March 1,2006 */ public class XMLUtil { /* * defaulting to namespace aware doc builder */ protected static DocumentBuilder docBuilder=null; static { try { DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); docBuilder = dbf.newDocumentBuilder(); } catch (ParserConfigurationException e) { e.printStackTrace(); } } /** * Mostly for internal use, it returns a string of tabs used for indenting * tag text. * * @param howMany The number of tabs you want in your string * @return A string of the number of tab characters you requested */ public static String getTabString(int howMany) { StringBuffer sb = new StringBuffer(); for (int i=0;i0); if (textNode || cData) { if (textValued) { s.append(tabs); if (cData) { s.append(""); } else { s.append(tagValue.trim()); } s.append("\n"); } } else { s.append(tabs+"<"+tagName); NamedNodeMap atts = n.getAttributes(); if (atts!=null && atts.getLength()>0) { for (int k=0;k\n"); return s.toString(); } else if (n.getChildNodes().getLength()==1 && n.getChildNodes().item(0).getNodeName().equals("#text") && n.getChildNodes().item(0).getNodeValue().trim().length()<35) { //has only a short text node s.append(">"); s.append(n.getChildNodes().item(0).getNodeValue().trim()); s.append("\n"); return s.toString(); } else { s.append(">\n"); } } //recursion NodeList nl=n.getChildNodes(); int len=nl.getLength(); for (int i=0;i\n"); } return s.toString(); } /** * This formats a Node with the first nodes being flush left * * @param n the node to be formatted to a string * @return Correctly formatted node as a String */ public static String nodeToString(Node n) { return nodeToString(n,0); } /** * Returns a full format of the Document object as a string including * the xml header and any DOCTYPE info that may exist * * @param doc Document object * @return Correctly formatted Document as a String */ public static String docToString(Document doc) { //Header StringBuffer result = new StringBuffer("\n"); //DocType DocumentType dt = doc.getDoctype(); if (dt!=null) { result.append("\n"); } //Main xml result.append(nodeToString(doc.getLastChild())); return result.toString(); } /** * Takes a String that should be a corrrectly formed XML document and * parses it into a Document object. I'm a little worried about thread * safety here, it needs some investigation. * * @param xmlString A properly formed xml document * @return org.w3c.dom.Document object * @throws IOException * @throws SAXException */ public static Document stringToDoc(String xmlString) throws IOException,SAXException { return docBuilder.parse(new ByteArrayInputStream(xmlString.getBytes())); } /** * Creates a new Document to use as a default paramerer when calling * addResultSetToDoc(Document doc, ResultSet rs, String nodeName) with the given root node name and ResultSet * * @param rs The unread ResultSet to be parsed into a Document * @param rootNodeName The name you want the root node of the document to have * @return a Document object containing the entire contents returned by the ResultSet * @throws SQLException * */ public static Document resultSetToDoc(ResultSet rs, String rootNodeName) throws SQLException { Document doc = docBuilder.newDocument(); addResultSetToDoc(doc,rs,rootNodeName); return doc; } /** * This calls resultSetToDoc(ResultSet rs, String rootNodeName) with a default * root node name of ResultSet. see resultSetToDoc(ResultSet rs, String rootNodeName) * * @param rs The unread ResultSet to be parsed into a Document * @return a Document object containing the entire contents returned by the ResultSet * @throws SQLException */ public static Document resultSetToDoc(ResultSet rs) throws SQLException { return resultSetToDoc(rs,"ResultSet"); } /** * Takes an unread ResultSet and appends to a Document object. The document will * have a root node named from the parameter rootNodeName and child nodes * each named row. Each row will have one tag for each column * of the ResultSet named the same as the column name and containing a text * representation of the column value. If the root node does not exist, it will * be created. If the root node does exist each row will be appended after * the last existing row child. *
* At a later date I may actually add an attribute called type that would be set * to the actual column datatype, but there hasn't been any advantage to doing * so yet. * * @param doc The XML Document object that the to which the ResultSet will be appended * @param rs The unread ResultSet to be parsed into a Document * @param nodeName The name you want the root node of the document to have * @return a Document object containing the entire contents returned by the ResultSet * @throws SQLException */ public static void addResultSetToDoc(Document doc, ResultSet rs, String nodeName) throws SQLException { Element node=doc.createElement(nodeName); if (doc.getFirstChild()==null) { doc.appendChild(node); } else { doc.getFirstChild().appendChild(node); } if (rs!=null) { int colCount = rs.getMetaData().getColumnCount(); String[] colNames=new String[colCount]; for (int i=0;inodeName * * @param doc The Document for which the node will be created, for some reason all nodes are relative to a document * @param map The Map that will be converted to the node * @param nodeName the name you want for the main tag that will enclose all the tags generated from the Map object * @return a Node for the given document named from nodeName and containing the name/value pairs of the map as tag/values */ public static Node mapToNode(Document doc,Map map,String nodeName) { Element resultNode=doc.createElement(nodeName); Iterator keyIterator = map.keySet().iterator(); while (keyIterator.hasNext()) { String tagName=keyIterator.next().toString(); Element tempNode = doc.createElement(tagName); if (map.get(tagName)!=null){ Text tx = doc.createTextNode(map.get(tagName).toString()); tempNode.appendChild(tx); } resultNode.appendChild(tempNode); } return resultNode; } /** * Creates a Properties object from a node containing name and value pairs. Tries to auto-detect * the tag names based on the structure. The given node is expected to contain one or more nodes * with name and value tags. The first tag will be the name and the second will be the value. * Use the following code as an example: * * Document d=XMLUtil.stringToDoc("<props><prp><name>name1</name><value>value1</value></prp><prp><name>second</name><value>value2</value></prp></props>");
* Properties p= XMLUtil.nodeToProperties( XPathAPI.eval(d,"/props").nodelist().item(0));
* System.out.println(p);
*
* */ public static Properties nodeToProperties(Node node) throws TransformerException { if (node==null) return null; Properties props=new Properties(); //how many props are there? int pCount=(int)XPathAPI.eval(node,"count(./*)").num(); for (int i=0;i