Java tutorial
/* * 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 <http://www.gnu.org/licenses/>. */ package net.sf.jasperreports.engine.util; import java.awt.Color; import java.awt.GraphicsEnvironment; import java.awt.font.TextAttribute; import java.io.IOException; import java.io.StringReader; import java.lang.ref.SoftReference; import java.text.AttributedCharacterIterator; import java.text.AttributedCharacterIterator.Attribute; import java.text.AttributedString; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import net.sf.jasperreports.engine.JRPrintHyperlink; import net.sf.jasperreports.engine.JRPrintHyperlinkParameter; import net.sf.jasperreports.engine.JRPrintHyperlinkParameters; import net.sf.jasperreports.engine.JRRuntimeException; import net.sf.jasperreports.engine.base.JRBasePrintHyperlink; import net.sf.jasperreports.engine.fonts.FontFamily; import net.sf.jasperreports.engine.type.HyperlinkTypeEnum; import net.sf.jasperreports.engine.util.JRStyledText.Run; import net.sf.jasperreports.extensions.ExtensionsEnvironment; /** * @author Teodor Danciu (teodord@users.sourceforge.net) */ public class JRStyledTextParser implements ErrorHandler { private static final Log log = LogFactory.getLog(JRStyledTextParser.class); private static final Set<String> AVAILABLE_FONT_FACE_NAMES = new HashSet<String>(); static { //FIXME doing this in a static block obscures exceptions, move it to some other place try { //FIXMEFONT do some cache //FIXME these should be taken from the current JasperReportsContext List<FontFamily> families = ExtensionsEnvironment.getExtensionsRegistry() .getExtensions(FontFamily.class); for (Iterator<FontFamily> itf = families.iterator(); itf.hasNext();) { FontFamily family = itf.next(); AVAILABLE_FONT_FACE_NAMES.add(family.getName()); } //FIXME use JRGraphEnvInitializer AVAILABLE_FONT_FACE_NAMES.addAll( Arrays.asList(GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames())); } catch (Exception e) { log.error("Error while loading available fonts", e); throw e; } } /** * */ private static final String ROOT_START = "<st>"; private static final String ROOT_END = "</st>"; private static final String NODE_style = "style"; private static final String NODE_bold = "b"; private static final String NODE_italic = "i"; private static final String NODE_underline = "u"; private static final String NODE_sup = "sup"; private static final String NODE_sub = "sub"; private static final String NODE_font = "font"; private static final String NODE_br = "br"; private static final String NODE_li = "li"; private static final String NODE_a = "a"; private static final String NODE_param = "param"; private static final String ATTRIBUTE_fontName = "fontName"; private static final String ATTRIBUTE_fontFace = "face"; private static final String ATTRIBUTE_color = "color"; private static final String ATTRIBUTE_size = "size"; private static final String ATTRIBUTE_isBold = "isBold"; private static final String ATTRIBUTE_isItalic = "isItalic"; private static final String ATTRIBUTE_isUnderline = "isUnderline"; private static final String ATTRIBUTE_isStrikeThrough = "isStrikeThrough"; private static final String ATTRIBUTE_forecolor = "forecolor"; private static final String ATTRIBUTE_backcolor = "backcolor"; private static final String ATTRIBUTE_pdfFontName = "pdfFontName"; private static final String ATTRIBUTE_pdfEncoding = "pdfEncoding"; private static final String ATTRIBUTE_isPdfEmbedded = "isPdfEmbedded"; private static final String ATTRIBUTE_type = "type"; private static final String ATTRIBUTE_href = "href"; private static final String ATTRIBUTE_target = "target"; private static final String ATTRIBUTE_name = "name"; private static final String ATTRIBUTE_valueClass = "valueClass"; private static final String SPACE = " "; private static final String EQUAL_QUOTE = "=\""; private static final String QUOTE = "\""; private static final String LESS = "<"; private static final String LESS_SLASH = "</"; private static final String GREATER = ">"; /** * Thread local soft cache of instances. */ private static final ThreadLocal<SoftReference<JRStyledTextParser>> threadInstances = new ThreadLocal<SoftReference<JRStyledTextParser>>(); /** * */ private static final ThreadLocal<Locale> threadLocale = new ThreadLocal<Locale>(); /** * Return a cached instance. * * @return a cached instance */ public static JRStyledTextParser getInstance() { JRStyledTextParser instance = null; SoftReference<JRStyledTextParser> instanceRef = threadInstances.get(); if (instanceRef != null) { instance = instanceRef.get(); } if (instance == null) { instance = new JRStyledTextParser(); threadInstances.set(new SoftReference<JRStyledTextParser>(instance)); } return instance; } /** * */ public static void setLocale(Locale locale) { threadLocale.set(locale); } /** * */ public static Locale getLocale() { return threadLocale.get(); } /** * */ private DocumentBuilder documentBuilder; /** * */ private JRBasePrintHyperlink hyperlink; /** * */ private JRStyledTextParser() { try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setFeature(JRXmlUtils.FEATURE_DISALLOW_DOCTYPE, true); documentBuilder = factory.newDocumentBuilder(); documentBuilder.setErrorHandler(this); } catch (ParserConfigurationException e) { throw new JRRuntimeException(e); } } /** * */ public JRStyledText parse(Map<Attribute, Object> attributes, String text, Locale locale) throws SAXException { JRStyledText styledText = new JRStyledText(locale); Document document = null; try { document = documentBuilder.parse(new InputSource(new StringReader(ROOT_START + text + ROOT_END))); } catch (IOException e) { throw new JRRuntimeException(e); } hyperlink = null; parseStyle(styledText, document.getDocumentElement()); styledText.setGlobalAttributes(attributes); return styledText; } /** * Creates a styled text object by either parsing a styled text String or * by wrapping an unstyled String. * * @param parentAttributes the element-level styled text attributes * @param text the (either styled or unstyled) text * @param isStyledText flag indicating that the text is styled * @param locale the locale for the text * @return a styled text object */ public JRStyledText getStyledText(Map<Attribute, Object> parentAttributes, String text, boolean isStyledText, Locale locale) { JRStyledText styledText = null; if (isStyledText) { try { styledText = parse(parentAttributes, text, locale); } catch (SAXException e) { //ignore if invalid styled text and treat like normal text } } if (styledText == null) { // using the original String object instead without creating a buffer and a String copy styledText = new JRStyledText(locale, text, parentAttributes); } return styledText; } /** * Outputs a styled text String given a styled text instance. * * @param styledText the styled text object * @return the String styled text representation */ public String write(JRStyledText styledText) { return write(styledText.getGlobalAttributes(), styledText.getAttributedString().getIterator(), styledText.getText()); } /** * Outputs a styled text String given a set of element-level styled text * attributes and a styled text in the form of a String text and an iterator * of style attributes. * * @param parentAttrs the element-level styled text attributes * @param iterator iterator of styled text attributes * @param text the text * @return the String styled text representation */ public String write(Map<Attribute, Object> parentAttrs, AttributedCharacterIterator iterator, String text) { StringBuilder sb = new StringBuilder(); int runLimit = 0; while (runLimit < iterator.getEndIndex() && (runLimit = iterator.getRunLimit()) <= iterator.getEndIndex()) { String chunk = text.substring(iterator.getIndex(), runLimit); Map<Attribute, Object> attrs = iterator.getAttributes(); StringBuilder styleBuilder = writeStyleAttributes(parentAttrs, attrs); if (styleBuilder.length() > 0) { sb.append(LESS); sb.append(NODE_style); sb.append(styleBuilder.toString()); sb.append(GREATER); writeChunk(sb, parentAttrs, attrs, chunk); sb.append(LESS_SLASH); sb.append(NODE_style); sb.append(GREATER); } else { writeChunk(sb, parentAttrs, attrs, chunk); } iterator.setIndex(runLimit); } return sb.toString(); } /** * Outputs the String representation of a styled text chunk. * * @param styledText the styled text * @param startIndex the start index * @param endIndex the end index * @return the String styled text representation of the chunk delimited by * the start index and the end index * @see #write(Map, AttributedCharacterIterator, String) */ public String write(JRStyledText styledText, int startIndex, int endIndex) { AttributedCharacterIterator subIterator = new AttributedString( styledText.getAttributedString().getIterator(), startIndex, endIndex).getIterator(); String subText = styledText.getText().substring(startIndex, endIndex); return write(styledText.getGlobalAttributes(), subIterator, subText); } /** * */ public void writeChunk(StringBuilder sb, Map<Attribute, Object> parentAttrs, Map<Attribute, Object> attrs, String chunk) { Object value = attrs.get(TextAttribute.SUPERSCRIPT); Object oldValue = parentAttrs.get(TextAttribute.SUPERSCRIPT); boolean isSuper = false; boolean isSub = false; if (value != null && !value.equals(oldValue)) { isSuper = TextAttribute.SUPERSCRIPT_SUPER.equals(value); isSub = TextAttribute.SUPERSCRIPT_SUB.equals(value); } String scriptNode = isSuper ? NODE_sup : NODE_sub; if (isSuper || isSub) { sb.append(LESS); sb.append(scriptNode); sb.append(GREATER); } JRPrintHyperlink hlink = (JRPrintHyperlink) attrs.get(JRTextAttribute.HYPERLINK); if (hlink != null) { sb.append(LESS); sb.append(NODE_a); String href = hlink.getHyperlinkReference(); if (href != null && href.trim().length() > 0) { sb.append(SPACE); sb.append(ATTRIBUTE_href); sb.append(EQUAL_QUOTE); sb.append(JRStringUtil.htmlEncode(href)); sb.append(QUOTE); } String type = hlink.getLinkType(); if (type != null && type.trim().length() > 0) { sb.append(SPACE); sb.append(ATTRIBUTE_type); sb.append(EQUAL_QUOTE); sb.append(type); sb.append(QUOTE); } String target = hlink.getLinkTarget(); if (target != null && target.trim().length() > 0) { sb.append(SPACE); sb.append(ATTRIBUTE_target); sb.append(EQUAL_QUOTE); sb.append(target); sb.append(QUOTE); } sb.append(GREATER); JRPrintHyperlinkParameters parameters = hlink.getHyperlinkParameters(); if (parameters != null && parameters.getParameters() != null) { for (JRPrintHyperlinkParameter parameter : parameters.getParameters()) { sb.append(LESS); sb.append(NODE_param); sb.append(SPACE); sb.append(ATTRIBUTE_name); sb.append(EQUAL_QUOTE); sb.append(parameter.getName()); sb.append(QUOTE); sb.append(GREATER); if (parameter.getValue() != null) { String strValue = JRValueStringUtils.serialize(parameter.getValueClass(), parameter.getValue()); sb.append(JRStringUtil.xmlEncode(strValue)); } sb.append(LESS_SLASH); sb.append(NODE_param); sb.append(GREATER); } } } sb.append(JRStringUtil.xmlEncode(chunk)); if (hlink != null) { sb.append(LESS_SLASH); sb.append(NODE_a); sb.append(GREATER); } if (isSuper || isSub) { sb.append(LESS_SLASH); sb.append(scriptNode); sb.append(GREATER); } } /** * */ private void parseStyle(JRStyledText styledText, Node parentNode) throws SAXException { NodeList nodeList = parentNode.getChildNodes(); for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); if (node.getNodeType() == Node.TEXT_NODE) { styledText.append(node.getNodeValue()); } else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_style.equals(node.getNodeName())) { NamedNodeMap nodeAttrs = node.getAttributes(); Map<Attribute, Object> styleAttrs = new HashMap<Attribute, Object>(); if (nodeAttrs.getNamedItem(ATTRIBUTE_fontName) != null) { styleAttrs.put(TextAttribute.FAMILY, nodeAttrs.getNamedItem(ATTRIBUTE_fontName).getNodeValue()); } if (nodeAttrs.getNamedItem(ATTRIBUTE_isBold) != null) { styleAttrs.put(TextAttribute.WEIGHT, Boolean.valueOf(nodeAttrs.getNamedItem(ATTRIBUTE_isBold).getNodeValue()) ? TextAttribute.WEIGHT_BOLD : TextAttribute.WEIGHT_REGULAR); } if (nodeAttrs.getNamedItem(ATTRIBUTE_isItalic) != null) { styleAttrs.put(TextAttribute.POSTURE, Boolean.valueOf(nodeAttrs.getNamedItem(ATTRIBUTE_isItalic).getNodeValue()) ? TextAttribute.POSTURE_OBLIQUE : TextAttribute.POSTURE_REGULAR); } if (nodeAttrs.getNamedItem(ATTRIBUTE_isUnderline) != null) { styleAttrs.put(TextAttribute.UNDERLINE, Boolean.valueOf(nodeAttrs.getNamedItem(ATTRIBUTE_isUnderline).getNodeValue()) ? TextAttribute.UNDERLINE_ON : null); } if (nodeAttrs.getNamedItem(ATTRIBUTE_isStrikeThrough) != null) { styleAttrs.put(TextAttribute.STRIKETHROUGH, Boolean.valueOf(nodeAttrs.getNamedItem(ATTRIBUTE_isStrikeThrough).getNodeValue()) ? TextAttribute.STRIKETHROUGH_ON : null); } if (nodeAttrs.getNamedItem(ATTRIBUTE_size) != null) { styleAttrs.put(TextAttribute.SIZE, Float.valueOf(nodeAttrs.getNamedItem(ATTRIBUTE_size).getNodeValue())); } if (nodeAttrs.getNamedItem(ATTRIBUTE_pdfFontName) != null) { styleAttrs.put(JRTextAttribute.PDF_FONT_NAME, nodeAttrs.getNamedItem(ATTRIBUTE_pdfFontName).getNodeValue()); } if (nodeAttrs.getNamedItem(ATTRIBUTE_pdfEncoding) != null) { styleAttrs.put(JRTextAttribute.PDF_ENCODING, nodeAttrs.getNamedItem(ATTRIBUTE_pdfEncoding).getNodeValue()); } if (nodeAttrs.getNamedItem(ATTRIBUTE_isPdfEmbedded) != null) { styleAttrs.put(JRTextAttribute.IS_PDF_EMBEDDED, Boolean.valueOf(nodeAttrs.getNamedItem(ATTRIBUTE_isPdfEmbedded).getNodeValue())); } if (nodeAttrs.getNamedItem(ATTRIBUTE_forecolor) != null) { Color color = JRColorUtil.getColor(nodeAttrs.getNamedItem(ATTRIBUTE_forecolor).getNodeValue(), Color.black); styleAttrs.put(TextAttribute.FOREGROUND, color); } if (nodeAttrs.getNamedItem(ATTRIBUTE_backcolor) != null) { Color color = JRColorUtil.getColor(nodeAttrs.getNamedItem(ATTRIBUTE_backcolor).getNodeValue(), Color.black); styleAttrs.put(TextAttribute.BACKGROUND, color); } int startIndex = styledText.length(); parseStyle(styledText, node); styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length())); } else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_bold.equalsIgnoreCase(node.getNodeName())) { Map<Attribute, Object> styleAttrs = new HashMap<Attribute, Object>(); styleAttrs.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); int startIndex = styledText.length(); parseStyle(styledText, node); styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length())); } else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_italic.equalsIgnoreCase(node.getNodeName())) { Map<Attribute, Object> styleAttrs = new HashMap<Attribute, Object>(); styleAttrs.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); int startIndex = styledText.length(); parseStyle(styledText, node); styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length())); } else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_underline.equalsIgnoreCase(node.getNodeName())) { Map<Attribute, Object> styleAttrs = new HashMap<Attribute, Object>(); styleAttrs.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); int startIndex = styledText.length(); parseStyle(styledText, node); styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length())); } else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_sup.equalsIgnoreCase(node.getNodeName())) { Map<Attribute, Object> styleAttrs = new HashMap<Attribute, Object>(); styleAttrs.put(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUPER); int startIndex = styledText.length(); parseStyle(styledText, node); styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length())); } else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_sub.equalsIgnoreCase(node.getNodeName())) { Map<Attribute, Object> styleAttrs = new HashMap<Attribute, Object>(); styleAttrs.put(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUB); int startIndex = styledText.length(); parseStyle(styledText, node); styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length())); } else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_font.equalsIgnoreCase(node.getNodeName())) { NamedNodeMap nodeAttrs = node.getAttributes(); Map<Attribute, Object> styleAttrs = new HashMap<Attribute, Object>(); if (nodeAttrs.getNamedItem(ATTRIBUTE_size) != null) { styleAttrs.put(TextAttribute.SIZE, Float.valueOf(nodeAttrs.getNamedItem(ATTRIBUTE_size).getNodeValue())); } if (nodeAttrs.getNamedItem(ATTRIBUTE_color) != null) { Color color = JRColorUtil.getColor(nodeAttrs.getNamedItem(ATTRIBUTE_color).getNodeValue(), Color.black); styleAttrs.put(TextAttribute.FOREGROUND, color); } if (nodeAttrs.getNamedItem(ATTRIBUTE_fontFace) != null) { String fontFaces = nodeAttrs.getNamedItem(ATTRIBUTE_fontFace).getNodeValue(); StringTokenizer t = new StringTokenizer(fontFaces, ","); while (t.hasMoreTokens()) { String face = t.nextToken().trim(); if (AVAILABLE_FONT_FACE_NAMES.contains(face)) { styleAttrs.put(TextAttribute.FAMILY, face); break; } } } int startIndex = styledText.length(); parseStyle(styledText, node); styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length())); } else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_br.equalsIgnoreCase(node.getNodeName())) { styledText.append("\n"); int startIndex = styledText.length(); resizeRuns(styledText.getRuns(), startIndex, 1); parseStyle(styledText, node); styledText.addRun( new JRStyledText.Run(new HashMap<Attribute, Object>(), startIndex, styledText.length())); if (startIndex < styledText.length()) { styledText.append("\n"); resizeRuns(styledText.getRuns(), startIndex, 1); } } else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_li.equalsIgnoreCase(node.getNodeName())) { String tmpText = styledText.getText(); if (tmpText.length() > 0 && !tmpText.endsWith("\n")) { styledText.append("\n"); } styledText.append(" \u2022 "); int startIndex = styledText.length(); resizeRuns(styledText.getRuns(), startIndex, 1); parseStyle(styledText, node); styledText.addRun( new JRStyledText.Run(new HashMap<Attribute, Object>(), startIndex, styledText.length())); // if the text in the next node does not start with a '\n', or // if the next node is not a <li /> one, we have to append a new line Node nextNode = node.getNextSibling(); String textContent = getFirstTextOccurence(nextNode); if (nextNode != null && !((nextNode.getNodeType() == Node.ELEMENT_NODE && NODE_li.equalsIgnoreCase(nextNode.getNodeName()) || (textContent != null && textContent.startsWith("\n"))))) { styledText.append("\n"); resizeRuns(styledText.getRuns(), startIndex, 1); } } else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_a.equalsIgnoreCase(node.getNodeName())) { if (hyperlink == null) { NamedNodeMap nodeAttrs = node.getAttributes(); Map<Attribute, Object> styleAttrs = new HashMap<Attribute, Object>(); hyperlink = new JRBasePrintHyperlink(); hyperlink.setHyperlinkType(HyperlinkTypeEnum.REFERENCE); styleAttrs.put(JRTextAttribute.HYPERLINK, hyperlink); if (nodeAttrs.getNamedItem(ATTRIBUTE_href) != null) { hyperlink.setHyperlinkReference(nodeAttrs.getNamedItem(ATTRIBUTE_href).getNodeValue()); } if (nodeAttrs.getNamedItem(ATTRIBUTE_type) != null) { hyperlink.setLinkType(nodeAttrs.getNamedItem(ATTRIBUTE_type).getNodeValue()); } if (nodeAttrs.getNamedItem(ATTRIBUTE_target) != null) { hyperlink.setLinkTarget(nodeAttrs.getNamedItem(ATTRIBUTE_target).getNodeValue()); } int startIndex = styledText.length(); parseStyle(styledText, node); styledText.addRun(new JRStyledText.Run(styleAttrs, startIndex, styledText.length())); hyperlink = null; } else { throw new SAXException("Hyperlink <a> tags cannot be nested."); } } else if (node.getNodeType() == Node.ELEMENT_NODE && NODE_param.equalsIgnoreCase(node.getNodeName())) { if (hyperlink == null) { throw new SAXException("Hyperlink <param> tags must appear inside an <a> tag only."); } else { NamedNodeMap nodeAttrs = node.getAttributes(); JRPrintHyperlinkParameter parameter = new JRPrintHyperlinkParameter(); if (nodeAttrs.getNamedItem(ATTRIBUTE_name) != null) { parameter.setName(nodeAttrs.getNamedItem(ATTRIBUTE_name).getNodeValue()); } if (nodeAttrs.getNamedItem(ATTRIBUTE_valueClass) != null) { parameter.setValueClass(nodeAttrs.getNamedItem(ATTRIBUTE_valueClass).getNodeValue()); } String strValue = node.getTextContent(); if (strValue != null) { Object value = JRValueStringUtils.deserialize(parameter.getValueClass(), strValue); parameter.setValue(value); } hyperlink.addHyperlinkParameter(parameter); } } else if (node.getNodeType() == Node.ELEMENT_NODE) { String nodeName = "<" + node.getNodeName() + ">"; throw new SAXException("Tag " + nodeName + " is not a valid styled text tag."); } } } /** * */ private void resizeRuns(List<Run> runs, int startIndex, int count) { for (int j = 0; j < runs.size(); j++) { JRStyledText.Run run = runs.get(j); if (run.startIndex <= startIndex && run.endIndex > startIndex - count) { run.endIndex += count; } } } /** * */ private StringBuilder writeStyleAttributes(Map<Attribute, Object> parentAttrs, Map<Attribute, Object> attrs) { StringBuilder sb = new StringBuilder(); Object value = attrs.get(TextAttribute.FAMILY); Object oldValue = parentAttrs.get(TextAttribute.FAMILY); if (value != null && !value.equals(oldValue)) { sb.append(SPACE); sb.append(ATTRIBUTE_fontName); sb.append(EQUAL_QUOTE); sb.append(value); sb.append(QUOTE); } value = attrs.get(TextAttribute.WEIGHT); oldValue = parentAttrs.get(TextAttribute.WEIGHT); if (value != null && !value.equals(oldValue)) { sb.append(SPACE); sb.append(ATTRIBUTE_isBold); sb.append(EQUAL_QUOTE); sb.append(value.equals(TextAttribute.WEIGHT_BOLD)); sb.append(QUOTE); } value = attrs.get(TextAttribute.POSTURE); oldValue = parentAttrs.get(TextAttribute.POSTURE); if (value != null && !value.equals(oldValue)) { sb.append(SPACE); sb.append(ATTRIBUTE_isItalic); sb.append(EQUAL_QUOTE); sb.append(value.equals(TextAttribute.POSTURE_OBLIQUE)); sb.append(QUOTE); } value = attrs.get(TextAttribute.UNDERLINE); oldValue = parentAttrs.get(TextAttribute.UNDERLINE); if ((value == null && oldValue != null) || (value != null && !value.equals(oldValue))) { sb.append(SPACE); sb.append(ATTRIBUTE_isUnderline); sb.append(EQUAL_QUOTE); sb.append(value != null); sb.append(QUOTE); } value = attrs.get(TextAttribute.STRIKETHROUGH); oldValue = parentAttrs.get(TextAttribute.STRIKETHROUGH); if ((value == null && oldValue != null) || (value != null && !value.equals(oldValue))) { sb.append(SPACE); sb.append(ATTRIBUTE_isStrikeThrough); sb.append(EQUAL_QUOTE); sb.append(value != null); sb.append(QUOTE); } value = attrs.get(TextAttribute.SIZE); oldValue = parentAttrs.get(TextAttribute.SIZE); if (value != null && !value.equals(oldValue)) { sb.append(SPACE); sb.append(ATTRIBUTE_size); sb.append(EQUAL_QUOTE); sb.append(value); sb.append(QUOTE); } value = attrs.get(JRTextAttribute.PDF_FONT_NAME); oldValue = parentAttrs.get(JRTextAttribute.PDF_FONT_NAME); if (value != null && !value.equals(oldValue)) { sb.append(SPACE); sb.append(ATTRIBUTE_pdfFontName); sb.append(EQUAL_QUOTE); sb.append(value); sb.append(QUOTE); } value = attrs.get(JRTextAttribute.PDF_ENCODING); oldValue = parentAttrs.get(JRTextAttribute.PDF_ENCODING); if (value != null && !value.equals(oldValue)) { sb.append(SPACE); sb.append(ATTRIBUTE_pdfEncoding); sb.append(EQUAL_QUOTE); sb.append(value); sb.append(QUOTE); } value = attrs.get(JRTextAttribute.IS_PDF_EMBEDDED); oldValue = parentAttrs.get(JRTextAttribute.IS_PDF_EMBEDDED); if (value != null && !value.equals(oldValue)) { sb.append(SPACE); sb.append(ATTRIBUTE_isPdfEmbedded); sb.append(EQUAL_QUOTE); sb.append(value); sb.append(QUOTE); } value = attrs.get(TextAttribute.FOREGROUND); oldValue = parentAttrs.get(TextAttribute.FOREGROUND); if (value != null && !value.equals(oldValue)) { sb.append(SPACE); sb.append(ATTRIBUTE_forecolor); sb.append(EQUAL_QUOTE); sb.append(JRColorUtil.getCssColor((Color) value)); sb.append(QUOTE); } value = attrs.get(TextAttribute.BACKGROUND); oldValue = parentAttrs.get(TextAttribute.BACKGROUND); if (value != null && !value.equals(oldValue)) { sb.append(SPACE); sb.append(ATTRIBUTE_backcolor); sb.append(EQUAL_QUOTE); sb.append(JRColorUtil.getCssColor((Color) value)); sb.append(QUOTE); } return sb; } /** * The method returns the first text occurrence in a given node element * @param node * @return String */ private String getFirstTextOccurence(Node node) { if (node != null) { if (node.getNodeValue() != null) { return node.getNodeValue(); } NodeList nodeList = node.getChildNodes(); for (int i = 0; i < nodeList.getLength(); i++) { String firstOccurence = getFirstTextOccurence(nodeList.item(i)); if (firstOccurence != null) { return firstOccurence; } } } return null; } @Override public void error(SAXParseException e) { if (log.isErrorEnabled()) { log.error("Error parsing styled text.", e); } } @Override public void fatalError(SAXParseException e) { if (log.isFatalEnabled()) { log.fatal("Error parsing styled text.", e); } } @Override public void warning(SAXParseException e) { if (log.isWarnEnabled()) { log.warn("Error parsing styled text.", e); } } }