blob: aeae91b5da5a1cdd65d9b1633c2730492641eb77 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.taglibs.standard.tag.common.xml;
import java.io.Reader;
import java.io.StringReader;
import java.util.List;
import jakarta.servlet.jsp.JspException;
import jakarta.servlet.jsp.JspTagException;
import jakarta.servlet.jsp.PageContext;
import jakarta.servlet.jsp.tagext.BodyTagSupport;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.taglibs.standard.resources.Resources;
import org.apache.taglibs.standard.tag.common.core.Util;
import org.apache.taglibs.standard.util.UnclosableWriter;
import org.apache.taglibs.standard.util.XmlUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
/**
* <p>Support for tag handlers for &lt;transform&gt;, the XML transformation
* tag.</p>
*
* @author Shawn Bayern
*/
public abstract class TransformSupport extends BodyTagSupport {
//*********************************************************************
// Protected state
protected Object xml; // attribute
protected boolean xmlSpecified; // true if xml attribute was specified
protected String xmlSystemId; // attribute
protected Object xslt; // attribute
protected String xsltSystemId; // attribute
protected Result result; // attribute
//*********************************************************************
// Private state
private String var; // 'var' attribute
private int scope; // processed 'scope' attr
private Transformer t; // actual Transformer
private XmlUtil.JstlEntityResolver entityResolver;
private XmlUtil.JstlUriResolver uriResolver;
//*********************************************************************
// Constructor and initialization
public TransformSupport() {
init();
}
private void init() {
xml = xslt = null;
xmlSpecified = false;
xmlSystemId = xsltSystemId = null;
var = null;
result = null;
scope = PageContext.PAGE_SCOPE;
}
//*********************************************************************
// Tag logic
@Override
public int doStartTag() throws JspException {
// set up transformer in the start tag so that nested <param> tags can set parameters directly
if (xslt == null) {
throw new JspTagException(Resources.getMessage("TRANSFORM_XSLT_IS_NULL"));
}
Source source;
try {
if (xslt instanceof Source) {
source = (Source) xslt;
} else if (xslt instanceof String) {
String s = (String) xslt;
s = s.trim();
if (s.length() == 0) {
throw new JspTagException(Resources.getMessage("TRANSFORM_XSLT_IS_EMPTY"));
}
source = XmlUtil.newSAXSource(new StringReader(s), xsltSystemId, entityResolver);
} else if (xslt instanceof Reader) {
source = XmlUtil.newSAXSource((Reader) xslt, xsltSystemId, entityResolver);
} else {
throw new JspTagException(Resources.getMessage("TRANSFORM_XSLT_UNSUPPORTED_TYPE", xslt.getClass()));
}
} catch (SAXException|ParserConfigurationException e) {
throw new JspException(e);
}
try {
t = XmlUtil.newTransformer(source, uriResolver);
t.setURIResolver(uriResolver);
} catch (TransformerConfigurationException e) {
throw new JspTagException(e);
}
return EVAL_BODY_BUFFERED;
}
@Override
public int doEndTag() throws JspException {
try {
Source source = xmlSpecified ? getSourceFromXmlAttribute() : getSourceFromBodyContent();
// Conduct the transformation
if (var != null) {
// Save the result to var.
Document d = XmlUtil.newEmptyDocument();
Result doc = new DOMResult(d);
t.transform(source, doc);
pageContext.setAttribute(var, d, scope);
} else {
// Write to out if result is not specified.
Result out = result;
if (out == null) {
out = new StreamResult(new UnclosableWriter(pageContext.getOut()));
}
t.transform(source, out);
}
return EVAL_PAGE;
} catch (TransformerException|SAXException|ParserConfigurationException e) {
throw new JspException(e);
} finally {
t = null;
}
}
// Releases any resources we may have (or inherit)
@Override
public void release() {
super.release();
init();
}
@Override
public void setPageContext(PageContext pageContext) {
super.setPageContext(pageContext);
uriResolver = pageContext == null ? null : new XmlUtil.JstlUriResolver(pageContext);
entityResolver = pageContext == null ? null : new XmlUtil.JstlEntityResolver(pageContext);
}
//*********************************************************************
// Public methods for subtags
/**
* Sets (adds) a transformation parameter on our transformer.
*/
public void addParameter(String name, Object value) {
t.setParameter(name, value);
}
//*********************************************************************
// Utility methods
/**
* Return the Source for a document specified in the "doc" or "xml" attribute.
*
* @return the document Source
* @throws JspTagException if there is a problem with the attribute
*/
Source getSourceFromXmlAttribute() throws JspTagException, SAXException, ParserConfigurationException {
Object xml = this.xml;
if (xml == null) {
throw new JspTagException(Resources.getMessage("TRANSFORM_XML_IS_NULL"));
}
// other JSTL XML tags may produce a list
if (xml instanceof List) {
List<?> list = (List<?>) xml;
if (list.size() != 1) {
throw new JspTagException(Resources.getMessage("TRANSFORM_XML_LIST_SIZE"));
}
xml = list.get(0);
}
if (xml instanceof Source) {
return (Source) xml;
}
if (xml instanceof String) {
String s = (String) xml;
s = s.trim();
if (s.length() == 0) {
throw new JspTagException(Resources.getMessage("TRANSFORM_XML_IS_EMPTY"));
}
return XmlUtil.newSAXSource(new StringReader(s), xmlSystemId, entityResolver);
}
if (xml instanceof Reader) {
return XmlUtil.newSAXSource((Reader) xml, xmlSystemId, entityResolver);
}
if (xml instanceof Node) {
return new DOMSource((Node) xml, xmlSystemId);
}
throw new JspTagException(Resources.getMessage("TRANSFORM_XML_UNSUPPORTED_TYPE", xml.getClass()));
}
/**
* Return the Source for a document specified as body content.
*
* @return the document Source
* @throws JspTagException if there is a problem with the body content
*/
Source getSourceFromBodyContent() throws JspTagException, SAXException, ParserConfigurationException {
if (bodyContent == null) {
throw new JspTagException(Resources.getMessage("TRANSFORM_BODY_IS_NULL"));
}
String s = bodyContent.getString();
if (s == null) {
throw new JspTagException(Resources.getMessage("TRANSFORM_BODY_CONTENT_IS_NULL"));
}
s = s.trim();
if (s.length() == 0) {
throw new JspTagException(Resources.getMessage("TRANSFORM_BODY_IS_EMPTY"));
}
return XmlUtil.newSAXSource(new StringReader(s), xmlSystemId, entityResolver);
}
//*********************************************************************
// Tag attributes
public void setVar(String var) {
this.var = var;
}
public void setScope(String scope) {
this.scope = Util.getScope(scope);
}
}