net.sf.jasperreports.engine.util.JRXmlWriteHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jasperreports Show documentation
Show all versions of jasperreports Show documentation
Free Java Reporting Library
/*
* JasperReports - Free Java Reporting Library.
* Copyright (C) 2001 - 2019 TIBCO Software Inc. All rights reserved.
* http://www.jaspersoft.com
*
* Unless you have purchased a commercial license agreement from Jaspersoft,
* the following license terms apply:
*
* This program is part of JasperReports.
*
* JasperReports is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JasperReports is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with JasperReports. If not, see .
*/
package net.sf.jasperreports.engine.util;
import java.awt.Color;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.sf.jasperreports.engine.JRExpression;
import net.sf.jasperreports.engine.type.JREnum;
import net.sf.jasperreports.engine.type.NamedEnum;
/**
* @author Lucian Chirita ([email protected])
*/
public class JRXmlWriteHelper
{
public static final String XML_SCHEMA_NAMESPACE = "http://www.w3.org/2001/XMLSchema-instance";
public static final String XML_SCHEMA_NAMESPACE_PREFIX = "xsi";
public static final String XML_NAMESPACE_ATTRIBUTE = "xmlns";
public static final String XML_SCHEMA_LOCATION_ATTRIBUTE = "schemaLocation";
private final Writer writer;
private final List indents;
private int indent;
private final List elementStack;
private StringBuilder builder;
private StackElement lastElement;
protected static class Attribute
{
String name;
String value;
Attribute(String name, String value)
{
this.name = name;
this.value = value;
}
}
protected static class StackElement
{
String name;
List atts;
boolean hasChildren;
XmlNamespace namespace;
String qName;
boolean hasAttributes = false;
StackElement(String name, XmlNamespace namespace)
{
this.name = name;
this.atts = new ArrayList();
this.hasChildren = false;
this.namespace = namespace;
this.qName = getQualifiedName(this.name, this.namespace);
}
void addAttribute(String attName, String value)
{
addAttribute(attName, value, true);
}
void addAttribute(String attName, String value, boolean count)
{
atts.add(new Attribute(attName, value));
hasAttributes |= count;
}
}
public JRXmlWriteHelper(Writer writer)
{
this.writer = writer;
indents = new ArrayList();
indent = 0;
elementStack = new ArrayList();
lastElement = null;
clearBuffer();
}
public void writeProlog(String encoding) throws IOException
{
writer.write("\n");
}
public void writePublicDoctype(String rootElement, String description, String dtdLocation) throws IOException
{
writer.write("\n\n");
}
public void startElement(String name)
{
startElement(name, null);
}
public void startElement(String name, XmlNamespace namespace)
{
boolean startsNS = false;
XmlNamespace elementNS = null;
if (namespace == null)
{
elementNS = getParentNamespace();
}
else
{
elementNS = findContextNamespace(namespace.getNamespaceURI());
if (elementNS == null)
{
startsNS = true;
elementNS = namespace;
}
}
++indent;
lastElement = new StackElement(name, elementNS);
elementStack.add(lastElement);
if (startsNS)
{
String xmlnsAttr = XML_NAMESPACE_ATTRIBUTE;
if (namespace.getPrefix() != null)
{
xmlnsAttr += ":" + namespace.getPrefix();
}
lastElement.addAttribute(xmlnsAttr, namespace.getNamespaceURI(), false);
if (indent == 1)//root element
{
//add the XML Schema namespace
String xmlSchemaXmlns = XML_NAMESPACE_ATTRIBUTE + ":" + XML_SCHEMA_NAMESPACE_PREFIX;
lastElement.addAttribute(xmlSchemaXmlns, XML_SCHEMA_NAMESPACE, false);
}
if (namespace.getSchemaURI() != null)
{
String schemaLocationAttr = getQualifiedName(
XML_SCHEMA_LOCATION_ATTRIBUTE, XML_SCHEMA_NAMESPACE_PREFIX);
String schemaLocation = namespace.getNamespaceURI()
+ " " + namespace.getSchemaURI();
lastElement.addAttribute(schemaLocationAttr, schemaLocation, false);
}
}
}
protected XmlNamespace getParentNamespace()
{
return lastElement == null ? null : lastElement.namespace;
}
protected XmlNamespace findContextNamespace(String namespaceURI)
{
XmlNamespace ns = null;
for (ListIterator it = elementStack.listIterator(elementStack.size()); it.hasPrevious();)
{
StackElement element = it.previous();
if (element.namespace != null && namespaceURI.equals(element.namespace.getNamespaceURI()))
{
ns = element.namespace;
break;
}
}
return ns;
}
protected static String getQualifiedName(String name, XmlNamespace ns)
{
return ns == null ? name : getQualifiedName(name, ns.getPrefix());
}
protected static String getQualifiedName(String name, String nsPrefix)
{
String qName;
if (nsPrefix == null)
{
qName = name;
}
else
{
qName = nsPrefix + ":" + name;
}
return qName;
}
protected void writeParents(boolean content) throws IOException
{
int stackSize = elementStack.size();
int startWrite = stackSize - 1;
while (startWrite >= 0)
{
StackElement element = elementStack.get(startWrite);
if (element.hasChildren)
{
break;
}
if (startWrite < stackSize - 1)
{
element.hasChildren = true;
}
else
{
element.hasChildren |= content;
}
--startWrite;
}
for (int i = startWrite + 1; i < stackSize; ++i)
{
StackElement element = elementStack.get(i);
writeElementAttributes(element, i);
}
}
public void writeCDATA(String data) throws IOException
{
if (data != null)
{
writeParents(true);
builder.append(getIndent(indent));
builder.append("\n");
flushBuffer();
}
}
public void writeCDATAElement(String name, String data) throws IOException
{
writeCDATAElement(name, getParentNamespace(), data);
}
public void writeCDATAElement(String name, XmlNamespace namespace,
String data) throws IOException
{
if (data != null)
{
writeParents(true);
builder.append(getIndent(indent));
builder.append('<');
String qName = getQualifiedName(name, namespace);
builder.append(qName);
builder.append(">\n");
flushBuffer();
}
}
public void writeCDATAElement(String name, String data, String attName, String attValue) throws IOException
{
writeCDATAElement(name, data, attName, (Object) attValue);
}
public void writeCDATAElement(String name, String data, String attName, Object attValue) throws IOException
{
writeCDATAElement(name, getParentNamespace(), data, attName, attValue);
}
public void writeCDATAElement(
String name,
XmlNamespace namespace,
String data,
String attName,
Object attValue
) throws IOException
{
writeCDATAElement(name, namespace, data, new String[]{attName}, new Object[]{attValue});
}
public void writeCDATAElement(
String name,
XmlNamespace namespace,
String data,
String[] attNames,
Object[] attValues
) throws IOException
{
if (data != null)
{
writeParents(true);
builder.append(getIndent(indent));
builder.append('<');
String qName = getQualifiedName(name, namespace);
builder.append(qName);
if (attNames != null)
{
for (int i = 0; i < attNames.length; i++)
{
if (attValues[i] != null)
{
builder.append(' ');
builder.append(attNames[i]);
builder.append("=\"");
builder.append(attValues[i]);
builder.append("\"");
}
}
}
builder.append(">\n");
flushBuffer();
}
}
protected void writeElementAttributes(StackElement element, int level) throws IOException
{
builder.append(getIndent(level));
builder.append('<');
builder.append(element.qName);
for (Iterator i = element.atts.iterator(); i.hasNext();)
{
Attribute att = i.next();
builder.append(' ');
builder.append(att.name);
builder.append("=\"");
builder.append(att.value);
builder.append('"');
}
if (element.hasChildren)
{
builder.append(">\n");
}
else
{
builder.append("/>\n");
}
flushBuffer();
}
public void closeElement() throws IOException
{
closeElement(false);
}
public void closeElement(boolean skipIfEmpty) throws IOException
{
--indent;
if (skipIfEmpty && !lastElement.hasAttributes && !lastElement.hasChildren)
{
clearBuffer();
}
else
{
writeParents(false);
if (lastElement.hasChildren)
{
builder.append(getIndent(indent));
builder.append("\n");
flushBuffer();
}
}
elementStack.remove(indent);
lastElement = indent > 0 ? (StackElement) elementStack.get(indent - 1) : null;
}
protected char[] getIndent(int level)
{
if (level >= indents.size())
{
for (int i = indents.size(); i <= level; ++i)
{
char[] str = new char[i];
Arrays.fill(str, '\t');
indents.add(str);
}
}
return indents.get(level);
}
protected void flushBuffer() throws IOException
{
writer.write(builder.toString());
clearBuffer();
}
protected void clearBuffer()
{
builder = new StringBuilder();
}
/**
* @deprecated Replaced by {@link #writeExpression(String, JRExpression)}.
*/
public void writeExpression(String name, JRExpression expression, boolean writeClass) throws IOException
{
writeExpression(name, expression, writeClass, null);
}
public void writeExpression(String name, XmlNamespace namespace, JRExpression expression) throws IOException
{
if (expression != null)
{
writeCDATAElement(name, namespace, expression.getText());
}
}
public void writeExpression(String name, JRExpression expression) throws IOException
{
writeExpression(name, getParentNamespace(), expression);
}
/**
* @deprecated Replaced by {@link #writeExpression(String, XmlNamespace, JRExpression)}.
*/
public void writeExpression(String name, XmlNamespace namespace,
JRExpression expression, boolean writeClass) throws IOException
{
writeExpression(name, namespace, expression, writeClass, null);
}
/**
* @deprecated Replaced by {@link #writeExpression(String, JRExpression)}.
*/
public void writeExpression(String name,
JRExpression expression, boolean writeClass, String defaultClassName) throws IOException
{
writeExpression(name, getParentNamespace(), expression, writeClass, defaultClassName);
}
/**
* @deprecated Replaced by {@link #writeExpression(String, XmlNamespace, JRExpression)}.
*/
public void writeExpression(String name, XmlNamespace namespace,
JRExpression expression, boolean writeClass, String defaultClassName) throws IOException
{
if (expression != null)
{
if (writeClass &&
(defaultClassName == null || !defaultClassName.equals(expression.getValueClassName())))
{
writeCDATAElement(name, namespace, expression.getText(),
"class", expression.getValueClassName());
}
else
{
writeCDATAElement(name, namespace, expression.getText());
}
}
}
protected void writeAttribute(String name, String value)
{
lastElement.addAttribute(name, value);
}
public void addAttribute(String name, String value)
{
if (value != null)
{
writeAttribute(name, value);
}
}
public void addEncodedAttribute(String name, String value)
{
if (value != null)
{
writeAttribute(name, JRStringUtil.encodeXmlAttribute(value));
}
}
public void addAttribute(String name, String value, String defaultValue)
{
if (value != null && !value.equals(defaultValue))
{
writeAttribute(name, value);
}
}
public void addEncodedAttribute(String name, String value, String defaultValue)
{
if (value != null && !value.equals(defaultValue))
{
writeAttribute(name, JRStringUtil.encodeXmlAttribute(value));
}
}
public void addAttribute(String name, Object value)
{
if (value != null)
{
writeAttribute(name, String.valueOf(value));
}
}
public void addAttribute(String name, Number value, Number defaultValue)
{
if (value != null && !value.equals(defaultValue))
{
writeAttribute(name, String.valueOf(value));
}
}
public void addAttribute(String name, Float value, boolean withMinDecimals)
{
if (value != null)
{
Number number = value;
if (withMinDecimals && value.intValue() == value.floatValue())
{
number = value.intValue();
}
writeAttribute(name, String.valueOf(number));
}
}
public void addAttribute(String name, JREnum value)
{
addAttribute(name, (NamedEnum) value);
}
public void addAttribute(String name, NamedEnum value)
{
if (value != null)
{
writeAttribute(name, value.getName());
}
}
public void addAttribute(String name, JREnum value, JREnum defaultValue)
{
addAttribute(name, (NamedEnum) value, (NamedEnum) defaultValue);
}
public void addAttribute(String name, NamedEnum value, NamedEnum defaultValue)
{
if (value != null && !value.equals(defaultValue))
{
writeAttribute(name, value.getName());
}
}
public void addAttribute(String name, int value)
{
writeAttribute(name, String.valueOf(value));
}
public void addAttributePositive(String name, int value)
{
if (value > 0)
{
writeAttribute(name, String.valueOf(value));
}
}
public void addAttribute(String name, float value)
{
writeAttribute(name, String.valueOf(value));
}
public void addAttribute(String name, float value, float defaultValue)
{
if (value != defaultValue)
{
writeAttribute(name, String.valueOf(value));
}
}
public void addAttribute(String name, double value)
{
writeAttribute(name, String.valueOf(value));
}
public void addAttribute(String name, double value, double defaultValue)
{
if (value != defaultValue)
{
writeAttribute(name, String.valueOf(value));
}
}
public void addAttribute(String name, int value, int defaultValue)
{
if (value != defaultValue)
{
addAttribute(name, value);
}
}
public void addAttribute(String name, boolean value)
{
writeAttribute(name, String.valueOf(value));
}
public void addAttribute(String name, boolean value, boolean defaultValue)
{
if (value != defaultValue)
{
addAttribute(name, value);
}
}
public void addAttribute(String name, Color color)
{
if (color != null)
{
writeAttribute(name, JRColorUtil.getCssColor(color));
}
}
public void addAttribute(String name, Color value, Color defaultValue)
{
if (value != null && value.getRGB() != defaultValue.getRGB())
{
addAttribute(name, value);
}
}
public Writer getUnderlyingWriter()
{
return writer;
}
protected static final Pattern PATTERN_CDATA_CLOSE = Pattern.compile("\\]\\]\\>");
protected static final String ESCAPED_CDATA_CLOSE = "]]]]>";
protected static String encodeCDATA(String data)
{
if (data == null)
{
return null;
}
//replacing "]]>" by "]]]]>"
Matcher matcher = PATTERN_CDATA_CLOSE.matcher(data);
return matcher.replaceAll(ESCAPED_CDATA_CLOSE);
}
}