/* * FrontlineSMS <http://www.frontlinesms.com> * Copyright 2011 kiwanja * * This file is part of FrontlineSMS. * * FrontlineSMS 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. * * FrontlineSMS 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 FrontlineSMS. If not, see <http://www.gnu.org/licenses/>. */ package yo.sms.service; import java.text.CharacterIterator; import java.text.StringCharacterIterator; import java.util.HashMap; import java.util.Stack; import java.util.Map.Entry; public class XmlEntityBuilder { private StringBuilder entity; private Stack<String> xmlElementNames; public XmlEntityBuilder() { this.entity = new StringBuilder(); this.xmlElementNames = new Stack<String>(); this.entity.append("<?xml version=\"1.0\"?>"); } public String getStringEntity() { if (this.xmlElementNames.size() > 0) { throw new IllegalStateException("there are still outstanding elements that were not closed with writeEndElement"); } return this.entity.toString(); } public void writeStartElement(String elementName) { writeStartElement(elementName, "", ""); } public void writeStartElement(String elementName, String elementNamespace) { writeStartElement(elementName, elementNamespace, ""); } public void writeStartElement(String elementName, String namespaceUri, String namespacePrefix) { if (elementName == null || elementName.length() == 0) { throw new IllegalArgumentException("elementName must be non-empty"); } if (namespaceUri == null) { throw new IllegalArgumentException("namespaceUri cannot be null"); } if (namespacePrefix == null) { throw new IllegalArgumentException("namespacePrefix cannot be null"); } HashMap<String, String> attributes = null; if (namespaceUri.length() > 0) { attributes = new HashMap<String, String>(); String namespaceAttributeName = "xmlns"; if (namespacePrefix.length() > 0) { namespaceAttributeName += (":" + namespacePrefix); } attributes.put(namespaceAttributeName, namespaceUri); } writeStartElement(elementName, attributes); } /** * Overload that accepts a set of attributes. Assumes that the attribute names are prefix-qualified if that is * required */ public void writeStartElement(String elementName, HashMap<String, String> attributes) { if (elementName == null || elementName.length() == 0) { throw new IllegalArgumentException("elementName must be non-empty"); } this.xmlElementNames.push(elementName); this.entity.append("<" + elementName); if (attributes != null && !attributes.isEmpty()) { for (Entry<String, String> attribute : attributes.entrySet()) { this.entity.append(" " + attribute.getKey() + "=\"" + attribute.getValue() + "\""); } } this.entity.append(">"); } public void writeText(String text) { this.entity.append(escapeText(text)); } public void writeEndElement() { if (this.xmlElementNames.size() == 0) { throw new IllegalStateException("writeEndElement must be matched by an earlier call to writeStartElement"); } String elementName = this.xmlElementNames.pop(); this.entity.append("</" + elementName + ">"); } /** * Escapes an XML string (i.e. * becomes <br/>) There are 5 entities of interest (<, >, ", ', and &) */ private static String escapeText(String rawText) { StringBuilder escapedText = new StringBuilder(); StringCharacterIterator characterIterator = new StringCharacterIterator(rawText); char currentCharacter = characterIterator.current(); while (currentCharacter != CharacterIterator.DONE) { switch (currentCharacter) { case '<': escapedText.append("<"); break; case '>': escapedText.append(">"); break; case '"': escapedText.append("""); break; case '\'': escapedText.append("'"); break; case '&': escapedText.append("&"); break; default: escapedText.append(currentCharacter); break; } currentCharacter = characterIterator.next(); } return escapedText.toString(); } }