/** * Copyright 2004-2016 Riccardo Solmi. All rights reserved. * This file is part of the Whole Platform. * * The Whole Platform 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. * * The Whole Platform 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 the Whole Platform. If not, see <http://www.gnu.org/licenses/>. */ package org.whole.lang.xml.builders; import java.io.PrintWriter; import java.util.Stack; import org.whole.lang.builders.GenericIdentityBuilder; import org.whole.lang.operations.IPrettyPrintWriter; import org.whole.lang.operations.PrettyPrintWriter; import org.whole.lang.util.StringUtils; /** * @author Enrico Persiani */ public class XmlPrettyPrinterBuilder extends GenericIdentityBuilder implements IXmlBuilder { private IPrettyPrintWriter prettyPrintWriter; private Stack<Integer> childrenCountStack; private Stack<String> eventStack; private Stack<String> tagNameStack; private StringBuilder tagNameBuilder; private boolean tagNameBuilderEnable; public XmlPrettyPrinterBuilder(PrintWriter out) { this(new PrettyPrintWriter(out)); } public XmlPrettyPrinterBuilder(IPrettyPrintWriter out) { prettyPrintWriter = out; childrenCountStack = new Stack<Integer>(); childrenCountStack.push(-1); eventStack = new Stack<String>(); tagNameStack = new Stack<String>(); tagNameBuilder = new StringBuilder(); tagNameBuilderEnable = false; } protected IPrettyPrintWriter prettyPrintWriter() { return prettyPrintWriter; } private void incrementChildrenCount() { int count = childrenCountStack.pop(); childrenCountStack.push(count+1); } private void pushChildrenCount(int count) { childrenCountStack.push(count); } private int popChildrenCount() { return childrenCountStack.pop(); } private int peekChildrenCount() { return childrenCountStack.peek(); } private void schedulePrintAfterEvent(String event, String data) { eventStack.push(data); eventStack.push(event); } private void printAfterEvent(String event) { if (!eventStack.isEmpty() && event.equals(eventStack.peek())) { eventStack.pop(); print(eventStack.pop()); } } private void scheduleTagNameBuilder() { tagNameBuilderEnable = true; } private void appendTagNameBuilder(String data) { if (tagNameBuilderEnable) tagNameBuilder.append(data); } private void completeTagName(String data) { if (tagNameBuilderEnable) { tagNameBuilder.append(data); tagNameStack.push(tagNameBuilder.toString()); tagNameBuilder.setLength(0); tagNameBuilderEnable = false; } } private String popTagName() { return tagNameStack.pop(); } private boolean lastPrintedCharData = false; public void print(String data) { prettyPrintWriter().printRaw(data); lastPrintedCharData = false; } private void printCharData(String data) { prettyPrintWriter().printRaw(data); lastPrintedCharData = true; } public void Document_() { } public void _Document() { prettyPrintWriter().println(); } public void Document() { } public void Prolog_() { } public void _Prolog() { } public void Prolog() { } public void XMLDecl_() { print("<?xml"); } public void _XMLDecl() { print("?>"); prettyPrintWriter().println(); } public void XMLDecl() { } public void Version(String value) { print(" version=\""); print(value); print("\""); } public void Version() { } public void Encoding(String value) { print(" encoding=\""); print(value); print("\""); } public void Encoding() { } public void DocTypeDecl_() { print("<!DOCTYPE "); schedulePrintAfterEvent("Name", " "); } public void _DocTypeDecl() { print(">"); prettyPrintWriter().println(); } public void DocTypeDecl() { } public void SystemId_() { print("SYSTEM \""); } public void _SystemId() { print("\""); } public void SystemId() { } public void SystemLiteral() { } public void SystemLiteral(String value) { print(value); } public void PublicId_() { print("PUBLIC \""); schedulePrintAfterEvent("PubidLiteral", "\" \""); } public void _PublicId() { print("\""); } public void PublicId() { } public void PubidLiteral(String value) { print(value); printAfterEvent("PubidLiteral"); } public void PubidLiteral() { PubidLiteral(""); } public void Misc_() { } public void Misc_(int initialCapacity) { } public void _Misc() { } public void Misc() { } public void Comment_() { if (peekChildrenCount() == 0) { print(">"); prettyPrintWriter().println(); } else if (!lastPrintedCharData) prettyPrintWriter().println(); incrementChildrenCount(); print("<!--"); } public void _Comment() { print("-->"); } public void Comment() { } public void CommentText() { } public void CommentText(String value) { print(StringUtils.toXMLCommentText(value)); } public void Instruction(String value) { print(value); } public void Instruction() { } public void PI_() { if (peekChildrenCount() == 0) { print(">"); prettyPrintWriter().println(); } if (!lastPrintedCharData) prettyPrintWriter().println(); incrementChildrenCount(); print("<?"); schedulePrintAfterEvent("Name", " "); } public void _PI() { print("?>"); prettyPrintWriter().println(); } public void PI() { } public void Attributes_() { } public void Attributes_(int initialCapacity) { } public void _Attributes() { } public void Attributes() { } public void Content_(int initialCapacity) { } public void Content_() { } public void _Content() { } public void Content() { } public void Element_() { if (peekChildrenCount() == 0) { print(">"); prettyPrintWriter().println(); } else if (peekChildrenCount() > 0 && !lastPrintedCharData) prettyPrintWriter().println(); incrementChildrenCount(); pushChildrenCount(0); scheduleTagNameBuilder(); print("<"); prettyPrintWriter().setRelativeIndentation(+1); } public void _Element() { prettyPrintWriter().setRelativeIndentation(-1); int childrenAdded = popChildrenCount(); String tagName = popTagName(); if (childrenAdded == 0) print("/>"); else { if (!lastPrintedCharData) prettyPrintWriter().println(); print("</"); print(tagName); print(">"); } } public void Element() { } public void CharData(String value) { if (peekChildrenCount() == 0) print(">"); printCharData(StringUtils.toXMLCharData(value)); incrementChildrenCount(); } public void CharData() { } public void CDataSectData(String value) { print(StringUtils.toXMLCData(value)); } public void CDataSectData() { } public void CDataSect_() { if (peekChildrenCount() == 0) { print(">"); prettyPrintWriter().println(); } else if (!lastPrintedCharData) prettyPrintWriter().println(); incrementChildrenCount(); print("<![CDATA["); } public void CDataSect_(int initialCapacity) { CDataSect_(); } public void _CDataSect() { print("]]>"); prettyPrintWriter().println(); } public void CDataSect() { } public void Value(String value) { print(StringUtils.toXMLString(value)); } public void Value() { } public void Attribute_() { print(" "); schedulePrintAfterEvent("Name", "=\""); } public void _Attribute() { print("\""); } public void Attribute() { } public void Name(String value) { completeTagName(value); print(value); printAfterEvent("Name"); } public void Name() { Name(""); } public void NameSpace(String value) { if (value.length() > 0) { appendTagNameBuilder(value); appendTagNameBuilder(":"); print(value); print(":"); } } public void NameSpace() { } public void QualifiedName_() { } public void _QualifiedName() { } public void QualifiedName() { } public void Standalone(boolean value) { print(" standalone=\"" + (value ? "yes" : "no") + "\""); } public void Standalone() { } public void attributes() { } public void content() { } public void docTypeDecl() { } public void element() { } public void encoding() { } public void externalId() { } public void instruction() { } public void misc() { } public void name() { } public void nameSpace() { } public void prolog() { } public void pubidLiteral() { } public void standalone() { } public void systemLiteral() { } public void tag() { } public void text() { } public void value() { } public void version() { } public void visit() { } public void xmlDecl() { } }