001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.runtime.helpers; 020 021import java.io.InputStream; 022import java.util.Stack; 023 024import lucee.commons.io.IOUtil; 025import lucee.commons.io.res.Resource; 026import lucee.runtime.PageContext; 027import lucee.runtime.engine.ThreadLocalPageContext; 028import lucee.runtime.exp.PageException; 029import lucee.runtime.exp.PageRuntimeException; 030import lucee.runtime.op.Caster; 031import lucee.runtime.text.xml.XMLUtil; 032import lucee.runtime.type.Struct; 033import lucee.runtime.type.StructImpl; 034import lucee.runtime.type.UDF; 035import lucee.runtime.type.util.ArrayUtil; 036 037import org.xml.sax.Attributes; 038import org.xml.sax.InputSource; 039import org.xml.sax.SAXException; 040import org.xml.sax.SAXParseException; 041import org.xml.sax.XMLReader; 042import org.xml.sax.helpers.DefaultHandler; 043 044 045 046/** 047 * Sax Parse with callback to CFC Methods 048 */ 049public final class XMLEventParser extends DefaultHandler { 050 051 private UDF startDocument; 052 private UDF startElement; 053 private UDF body; 054 private UDF endElement; 055 private UDF endDocument; 056 private UDF error; 057 058 private Stack<StringBuilder> bodies=new Stack<StringBuilder>(); 059 private PageContext pc; 060 private Struct att; 061 /** 062 * Field <code>DEFAULT_SAX_PARSER</code> 063 */ 064 public final static String DEFAULT_SAX_PARSER="org.apache.xerces.parsers.SAXParser"; 065 066 /** 067 * constructor of the class 068 * @param pc 069 * @param startDocument 070 * @param startElement 071 * @param body 072 * @param endElement 073 * @param endDocument 074 * @param error 075 */ 076 public XMLEventParser( 077 PageContext pc, 078 UDF startDocument, 079 UDF startElement, 080 UDF body, 081 UDF endElement, 082 UDF endDocument, 083 UDF error) { 084 085 this.pc=pc; 086 this.startDocument=startDocument; 087 this.startElement=startElement; 088 this.body=body; 089 this.endElement=endElement; 090 this.endDocument=endDocument; 091 this.error=error; 092 093 } 094 095 /** 096 * start execution of the parser 097 * @param xmlFile 098 * @throws PageException 099 */ 100 public void start(Resource xmlFile) throws PageException { 101 start(xmlFile,DEFAULT_SAX_PARSER); 102 } 103 104 /** 105 * start execution of the parser 106 * @param xmlFile 107 * @param saxParserCass 108 * @throws PageException 109 */ 110 public void start(Resource xmlFile,String saxParserCass) throws PageException { 111 InputStream is=null; 112 try { 113 XMLReader xmlReader = XMLUtil.createXMLReader(saxParserCass); 114 xmlReader.setContentHandler(this); 115 xmlReader.setErrorHandler(this); 116 xmlReader.parse(new InputSource(is=IOUtil.toBufferedInputStream(xmlFile.getInputStream()))); 117 } catch (Exception e) { 118 throw Caster.toPageException(e); 119 } 120 finally { 121 IOUtil.closeEL(is); 122 } 123 124 } 125 126 @Override 127 public void characters(char[] ch, int start, int length) throws SAXException { 128 bodies.peek().append(ch,start,length); 129 } 130 131 @Override 132 public void error(SAXParseException e) throws SAXException { 133 error(Caster.toPageException(e)); 134 } 135 @Override 136 public void fatalError(SAXParseException e) throws SAXException { 137 error(Caster.toPageException(e)); 138 } 139 @Override 140 public void startElement(String uri, String localName, String qName, 141 Attributes attributes) throws SAXException { 142 bodies.add(new StringBuilder()); 143 att = toStruct(attributes); 144 call(startElement,new Object[]{uri,localName,qName,att}); 145 } 146 147 @Override 148 public void endElement(String uri, String localName, String qName) throws SAXException { 149 call(body,new Object[]{bodies.pop().toString()}); 150 call(endElement,new Object[]{uri,localName,qName,att}); 151 } 152 153 @Override 154 public void startDocument() throws SAXException { 155 call(startDocument,ArrayUtil.OBJECT_EMPTY); 156 } 157 158 @Override 159 public void endDocument() throws SAXException { 160 call(endDocument,ArrayUtil.OBJECT_EMPTY); 161 } 162 163 /** 164 * call a user defined function 165 * @param udf 166 * @param arguments 167 */ 168 private void call(UDF udf, Object[] arguments) { 169 try { 170 udf.call(pc,arguments,false); 171 } catch (PageException pe) { 172 error(pe); 173 } 174 } 175 176 /** 177 * call back error function if a error occour 178 * @param pe 179 */ 180 private void error(PageException pe) { 181 if(error==null) throw new PageRuntimeException(pe); 182 try { 183 pc=ThreadLocalPageContext.get(pc); 184 error.call(pc,new Object[]{pe.getCatchBlock(pc.getConfig())},false); 185 } 186 catch (PageException e) {} 187 } 188 189 /** 190 * cast a Attributes object to a Struct 191 * @param att 192 * @return Attributes as Struct 193 */ 194 private Struct toStruct(Attributes att) { 195 int len=att.getLength(); 196 Struct sct=new StructImpl(); 197 for(int i=0;i<len;i++) { 198 sct.setEL(att.getQName(i),att.getValue(i)); 199 } 200 return sct; 201 } 202}