package net.sf.lab3f.xml; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.IOException; import java.io.StringWriter; import java.io.File; import java.io.FileOutputStream; import java.io.FileInputStream; import java.io.FilenameFilter; import java.io.OutputStreamWriter; import java.util.HashMap; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.traversal.NodeIterator; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import org.apache.xml.serializer.Serializer; import org.apache.xml.serializer.SerializerFactory; import org.apache.xml.serializer.OutputPropertiesFactory; import org.apache.xalan.templates.OutputProperties; import org.apache.xpath.XPathAPI; //import net.sf.lab3f.util.TuttiFruttiable; public class Main implements Xmlable { private HashMap <File, Transformer> transformers = new HashMap <File, Transformer> (); private HashMap <String, Document> docs = new HashMap <String, Document> (); private DocumentBuilder dBuilder; private TransformerFactory tFactory; private final String docType = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"" + " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"; private boolean asHtml; // private TuttiFruttiable tuttiFrutti; public void removeDocument(String id){docs.remove("id");} public void setAsHtml(boolean b){asHtml = b;} public String getDocumentAsXml(String id){return toString(docs.get(id));} public String getNodeAsXml(String id, String xpath){ String s = toString(getNodeByXPath(id, xpath)); if(s == null) return null; int n = s.indexOf("?>"); return (n > 0 && (xpath.trim().endsWith("node()") || xpath.lastIndexOf('@') > xpath.lastIndexOf('/'))) ? s = s.substring(n + 2) : s; } public void start() throws Exception { if(dBuilder == null){ DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance(); dBuilder = dFactory.newDocumentBuilder(); } System.out.println("[INFO] DOM holder starts."); if(!new File("xsl").exists())return; if(tFactory == null) tFactory = TransformerFactory.newInstance(); for(String s : new File("xsl").list( new FilenameFilter(){public boolean accept(File d, String n){return n.endsWith(".xsl");}})){ transformers.put(new File("xsl/" + s), tFactory.newTransformer(new StreamSource(new FileInputStream("xsl/" + s)))); } System.out.println("[INFO] XSL-transformers loaded."); } public void stop() throws Exception{transformers.clear();} public final void setInput(String id, InputStream is) throws IOException, SAXException{ if(is == null){ docs.remove(id); return; } docs.put(id, dBuilder.parse(is)); } public final void setInput(String id, String is){ try{setInput(id, new ByteArrayInputStream(is.getBytes("UTF8")));} catch(IOException ex){System.out.println(ex);} catch(SAXException ex){System.out.println(ex);} } private final String toString(Node node){ try{ StringWriter sw = new StringWriter(); Serializer serializer = SerializerFactory.getSerializer(OutputPropertiesFactory.getDefaultMethodProperties("xml")); serializer.setWriter(sw); serializer.asDOMSerializer().serialize(node); String s = sw.toString().trim(); return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>".equals(s) ? null : s; } catch(Exception ex){System.out.println(ex);return null;} } private final Node getNodeByXPath(String id, String xpath){ Document doc = docs.get(id); try{return XPathAPI.eval(doc, xpath).nodeset().nextNode();} catch(Exception ex){System.out.println(ex); return null;} } public void setAttribute(String id, String xpath, String name, String value){ ((Element)getNodeByXPath(id, xpath)).setAttribute(name, value) ; } public final boolean remove(String id, String xpath){return doSomthing(id, xpath, null, Operations.REMOVE);} public final boolean append(String id, String xpath, String newXml){ return doSomthing(id, xpath, newXml, Operations.APPEND);} public final boolean insert(String id, String xpath, String newXml){ return doSomthing(id, xpath, newXml, Operations.INSERT); } public final boolean replace(String id, String xpath, String newXml){ return doSomthing(id, xpath, newXml, Operations.REPLACE); } private enum Operations {APPEND, INSERT, REPLACE, REMOVE}; private final boolean doSomthing(String id, String xPath, String xml, Operations op){ Node oldEl = getNodeByXPath(id, xPath); if(oldEl == null) return false; Document doc = docs.get(id); try{ Node newEl = null; if(xml != null){ Document d1 = dBuilder.parse(new ByteArrayInputStream(xml.getBytes("UTF8"))); newEl = doc.importNode(d1.getDocumentElement(), true); } switch(op){ case APPEND: oldEl.appendChild(newEl); return true; case REPLACE: oldEl.getParentNode().replaceChild(newEl, oldEl); return true; case INSERT: oldEl.getParentNode().insertBefore(newEl, oldEl); return true; case REMOVE: oldEl.getParentNode().removeChild(oldEl); return true; default: return false; } } catch(Exception ex){System.out.println(ex);return false;} } public final void save(String id, String file){save(id, new File(file));} public final void save(String id, File file){ try{ OutputStreamWriter fw = new OutputStreamWriter(new FileOutputStream(file), "UTF8"); String s = toString(docs.get(id)); if(asHtml)s = docType + s.substring(s.indexOf("<html")); fw.write(s); fw.flush(); fw.close(); } catch(Exception ex){System.out.println(ex);} } // XSLT public final String transform(String name, String[] params, InputStream is){ try{ Transformer tr = transformers.get(new File("xsl/" + name)); if(tr == null) tr = transformers.get(new File("xsl/" + name + ".xsl")); if(params != null) for(String p : params) tr.setParameter(p.substring(0, p.indexOf('=')), p.substring(p.indexOf('=') + 1)); StreamSource src = new StreamSource(is); ByteArrayOutputStream baos = new ByteArrayOutputStream(); StreamResult res = new StreamResult(baos); tr.transform(src, res); baos.flush(); return new String(baos.toByteArray(), "UTF8"); } catch(Exception ex){System.out.println(ex);return null;} } public final String transform(String name, String[] params, String s){ try{return transform(name, params, new ByteArrayInputStream(s.getBytes("UTF8")));} catch(Exception ex){System.out.println(ex);return null;} } public final String transform(String name, String s){ try{return transform(name, null, new ByteArrayInputStream(s.getBytes("UTF8")));} catch(Exception ex){System.out.println(ex);return null;} } public final String transform(String name, InputStream is){ try{return transform(name, null, is);} catch(Exception ex){System.out.println(ex);return null;} } public void transform(String from, String to, String xsl, String[] params){ String s = transform(xsl, params, getDocumentAsXml(from)); try{setInput(to, new ByteArrayInputStream(s.getBytes("UTF8")));} catch(Exception ex){System.out.println(ex);} } public void transform(String from, String to, String xsl){transform(from, to, xsl, null);} private SAXParserFactory saxParserFactory; public boolean parse(InputStream is, Handlerable hnd){ try{ if(saxParserFactory == null)saxParserFactory = SAXParserFactory.newInstance(); DefaultHandler dh = new HandlerableHandler(hnd); SAXParser sax = saxParserFactory.newSAXParser(); sax.parse(is, dh); return true; } catch (Exception ex){System.out.println(ex);return false;} } private class HandlerableHandler extends DefaultHandler { StringBuffer sb = new StringBuffer(); Handlerable handler; HandlerableHandler(Handlerable h){handler = h;} public void startElement(String s1, String s2, String s3, Attributes attrs) throws SAXException { HashMap <String, String> map = new HashMap <String, String>(); for(int i = 0; i < attrs.getLength(); i++)map.put(attrs.getQName(i), attrs.getValue(i)); handler.startElement(s3, map); } public void endElement(String s1, String s2, String s3) throws SAXException { handler.setTextNodeContent(sb.toString().trim()); sb = new StringBuffer(); handler.endElement(s3); } public void characters(char[] cha, int n, int l){ sb.append(new String(cha, n, l)); } } }