package org.docbag.template.transformer.content.xml; import java.util.List; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; import org.docbag.Context; import org.docbag.expression.Expression; import org.docbag.expression.parser.DefaultRegExpParserFactory; import org.docbag.expression.parser.ExpressionParser; import org.docbag.expression.parser.ExpressionParserFactory; import org.docbag.template.transformer.TransformerException; import org.docbag.xml.XMLContent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * Implementation of {@link org.xml.sax.ContentHandler} that knows about embedded expressions. * * <p>It uses {@link ExpressionParser} to find embedded expressions within the template, * evaluates them and stores the evaluation result in the transformation.</p> * * <p>This class is NOT thread safe.</p> * * @author Jakub Torbicki */ public class XMLDynamicContentHandler extends DefaultHandler implements TemplateContentHandler<String> { private static final Logger log = LoggerFactory.getLogger(XMLDynamicContentHandler.class); private final ExpressionParser<String, String> parser; private final Context context; private XMLContent content; private StringBuilder currentElement; public XMLDynamicContentHandler(Context context) { this(context, new DefaultRegExpParserFactory()); } public XMLDynamicContentHandler(Context context, ExpressionParserFactory<String, String> parserFactory) { this.context = context; this.parser = parserFactory.getParser(); } public String getOutput() { return content.getContent(); } public boolean isComplete() { return content.isComplete(); } public void startDocument() throws SAXException { content = new XMLContent(); currentElement = new StringBuilder(); if (log.isDebugEnabled()) { log.debug("Starting to parse template"); } } public void endDocument() throws SAXException { content.complete(); currentElement = null; if (log.isDebugEnabled()) { log.debug("Template parsed!"); log.debug(content.getContent()); } } public void startPrefixMapping(String prefix, String uri) throws SAXException { content.enterNamespace(prefix, uri); } public void endPrefixMapping(String prefix) throws SAXException { content.leaveAllNamespaces(); } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { content.startElement(uri, localName, qName, attributes); } public void endElement(String uri, String localName, String qName) throws SAXException { String s = currentElement.toString().trim(); currentElement = new StringBuilder(); if (s.length() > 0) { List<String> tokens = parser.split(s); for (String token : tokens) { if (StringUtils.isNotEmpty(token)) { content.append(resolveDynamicContent(token)); } } } content.endElement(qName); } public void characters(char[] ch, int start, int length) throws SAXException { currentElement.append(ch, start, length); } private String resolveDynamicContent(String token) { String value = token; if (parser.isExpression(value)) { Expression<String, String> expression = parser.parseExpression(value); value = expression.getValue(context); if (value == null) { log.error("Could not evaluate Expression: " + token); throw new TransformerException("Could not evaluate Expression: " + token); } } else { // TODO Find out how to stop SAX from escaping text. value = StringEscapeUtils.escapeXml(value); } return value; } }