| /* XMLStreamWriterImpl.java -- | |
| Copyright (C) 2005 Free Software Foundation, Inc. | |
| This file is part of GNU Classpath. | |
| GNU Classpath is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 2, or (at your option) | |
| any later version. | |
| GNU Classpath 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 | |
| General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with GNU Classpath; see the file COPYING. If not, write to the | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
| 02110-1301 USA. | |
| Linking this library statically or dynamically with other modules is | |
| making a combined work based on this library. Thus, the terms and | |
| conditions of the GNU General Public License cover the whole | |
| combination. | |
| As a special exception, the copyright holders of this library give you | |
| permission to link this library with independent modules to produce an | |
| executable, regardless of the license terms of these independent | |
| modules, and to copy and distribute the resulting executable under | |
| terms of your choice, provided that you also meet, for each linked | |
| independent module, the terms and conditions of the license of that | |
| module. An independent module is a module which is not derived from | |
| or based on this library. If you modify this library, you may extend | |
| this exception to your version of the library, but you are not | |
| obligated to do so. If you do not wish to do so, delete this | |
| exception statement from your version. */ | |
| package gnu.xml.stream; | |
| import java.io.IOException; | |
| import java.io.Writer; | |
| import java.util.Enumeration; | |
| import java.util.HashSet; | |
| import java.util.LinkedList; | |
| import java.util.Set; | |
| import javax.xml.XMLConstants; | |
| import javax.xml.namespace.NamespaceContext; | |
| import javax.xml.stream.XMLStreamException; | |
| import javax.xml.stream.XMLStreamWriter; | |
| import org.xml.sax.helpers.NamespaceSupport; | |
| /** | |
| * Simple XML stream writer. | |
| * | |
| * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a> | |
| */ | |
| public class XMLStreamWriterImpl | |
| implements XMLStreamWriter | |
| { | |
| /** | |
| * The underlying character stream to write to. | |
| */ | |
| protected final Writer writer; | |
| /** | |
| * The encoding being used. | |
| * Note that this must match the encoding of the character stream. | |
| */ | |
| protected final String encoding; | |
| /** | |
| * Whether prefix defaulting is being used. | |
| * If true and a prefix has not been defined for a namespace specified on | |
| * an element or an attribute, a new prefix and namespace declaration will | |
| * be created. | |
| */ | |
| protected final boolean prefixDefaulting; | |
| /** | |
| * The namespace context used to determine the namespace-prefix mappings | |
| * in scope. | |
| */ | |
| protected NamespaceContext namespaceContext; | |
| /** | |
| * The stack of elements in scope. | |
| * Used to close the remaining elements. | |
| */ | |
| private LinkedList elements; | |
| /** | |
| * Whether a start element has been opened but not yet closed. | |
| */ | |
| private boolean inStartElement; | |
| /** | |
| * Whether we are in an empty element. | |
| */ | |
| private boolean emptyElement; | |
| private NamespaceSupport namespaces; | |
| private int count = 0; | |
| private boolean xml11; | |
| private boolean hasXML11RestrictedChars; | |
| /** | |
| * Constructor. | |
| * @see #writer | |
| * @see #encoding | |
| * @see #prefixDefaulting | |
| */ | |
| protected XMLStreamWriterImpl(Writer writer, String encoding, | |
| boolean prefixDefaulting) | |
| { | |
| this.writer = writer; | |
| this.encoding = encoding; | |
| this.prefixDefaulting = prefixDefaulting; | |
| elements = new LinkedList(); | |
| namespaces = new NamespaceSupport(); | |
| } | |
| /** | |
| * Write the end of a start-element event. | |
| * This will close the element if it was defined to be an empty element. | |
| */ | |
| private void endStartElement() | |
| throws IOException | |
| { | |
| if (!inStartElement) | |
| return; | |
| if (emptyElement) | |
| { | |
| writer.write('/'); | |
| elements.removeLast(); | |
| namespaces.popContext(); | |
| emptyElement = false; | |
| } | |
| writer.write('>'); | |
| inStartElement = false; | |
| } | |
| public void writeStartElement(String localName) | |
| throws XMLStreamException | |
| { | |
| try | |
| { | |
| if (!isName(localName)) | |
| throw new IllegalArgumentException("illegal Name: " + localName); | |
| endStartElement(); | |
| namespaces.pushContext(); | |
| writer.write('<'); | |
| writer.write(localName); | |
| elements.addLast(new String[] { null, localName }); | |
| inStartElement = true; | |
| } | |
| catch (IOException e) | |
| { | |
| XMLStreamException e2 = new XMLStreamException(e); | |
| e2.initCause(e); | |
| throw e2; | |
| } | |
| } | |
| public void writeStartElement(String namespaceURI, String localName) | |
| throws XMLStreamException | |
| { | |
| try | |
| { | |
| if (namespaceURI != null && !isURI(namespaceURI)) | |
| throw new IllegalArgumentException("illegal URI: " + namespaceURI); | |
| if (!isName(localName)) | |
| throw new IllegalArgumentException("illegal Name: " + localName); | |
| endStartElement(); | |
| namespaces.pushContext(); | |
| String prefix = getPrefix(namespaceURI); | |
| boolean isDeclared = (prefix != null); | |
| if (!isDeclared) | |
| { | |
| if (prefixDefaulting) | |
| prefix = createPrefix(namespaceURI); | |
| else | |
| throw new XMLStreamException("namespace " + namespaceURI + | |
| " has not been declared"); | |
| } | |
| writer.write('<'); | |
| if (!"".equals(prefix)) | |
| { | |
| writer.write(prefix); | |
| writer.write(':'); | |
| } | |
| writer.write(localName); | |
| inStartElement = true; | |
| if (!isDeclared) | |
| { | |
| writeNamespaceImpl(prefix, namespaceURI); | |
| } | |
| elements.addLast(new String[] { prefix, localName }); | |
| } | |
| catch (IOException e) | |
| { | |
| XMLStreamException e2 = new XMLStreamException(e); | |
| e2.initCause(e); | |
| throw e2; | |
| } | |
| } | |
| /** | |
| * Creates a new unique prefix in the document. | |
| * Subclasses may override this method to provide a suitably unique prefix | |
| * for the given namespace. | |
| * @param namespaceURI the namespace URI | |
| */ | |
| protected String createPrefix(String namespaceURI) | |
| { | |
| Set prefixes = new HashSet(); | |
| for (Enumeration e = namespaces.getPrefixes(); e.hasMoreElements(); ) | |
| prefixes.add(e.nextElement()); | |
| String ret; | |
| do | |
| { | |
| ret = "ns" + (count++); | |
| } | |
| while (prefixes.contains(ret)); | |
| return ret; | |
| } | |
| public void writeStartElement(String prefix, String localName, | |
| String namespaceURI) | |
| throws XMLStreamException | |
| { | |
| try | |
| { | |
| if (namespaceURI != null && !isURI(namespaceURI)) | |
| throw new IllegalArgumentException("illegal URI: " + namespaceURI); | |
| if (prefix != null && !isNCName(prefix)) | |
| throw new IllegalArgumentException("illegal NCName: " + prefix); | |
| if (!isNCName(localName)) | |
| throw new IllegalArgumentException("illegal NCName: " + localName); | |
| endStartElement(); | |
| namespaces.pushContext(); | |
| String currentPrefix = getPrefix(namespaceURI); | |
| boolean isCurrent = prefix.equals(currentPrefix); | |
| writer.write('<'); | |
| if (!"".equals(prefix)) | |
| { | |
| writer.write(prefix); | |
| writer.write(':'); | |
| } | |
| writer.write(localName); | |
| if (prefixDefaulting && !isCurrent) | |
| { | |
| writeNamespaceImpl(prefix, namespaceURI); | |
| } | |
| elements.addLast(new String[] { prefix, localName }); | |
| inStartElement = true; | |
| } | |
| catch (IOException e) | |
| { | |
| XMLStreamException e2 = new XMLStreamException(e); | |
| e2.initCause(e); | |
| throw e2; | |
| } | |
| } | |
| public void writeEmptyElement(String namespaceURI, String localName) | |
| throws XMLStreamException | |
| { | |
| writeStartElement(namespaceURI, localName); | |
| emptyElement = true; | |
| } | |
| public void writeEmptyElement(String prefix, String localName, | |
| String namespaceURI) | |
| throws XMLStreamException | |
| { | |
| writeStartElement(prefix, localName, namespaceURI); | |
| emptyElement = true; | |
| } | |
| public void writeEmptyElement(String localName) | |
| throws XMLStreamException | |
| { | |
| writeStartElement(localName); | |
| emptyElement = true; | |
| } | |
| public void writeEndElement() | |
| throws XMLStreamException | |
| { | |
| if (elements.isEmpty()) | |
| throw new IllegalStateException("no matching start element"); | |
| try | |
| { | |
| endStartElement(); | |
| String[] element = (String[]) elements.removeLast(); | |
| namespaces.popContext(); | |
| writer.write('<'); | |
| writer.write('/'); | |
| if (element[0] != null && !"".equals(element[0])) | |
| { | |
| writer.write(element[0]); | |
| writer.write(':'); | |
| } | |
| writer.write(element[1]); | |
| writer.write('>'); | |
| } | |
| catch (IOException e) | |
| { | |
| XMLStreamException e2 = new XMLStreamException(e); | |
| e2.initCause(e); | |
| throw e2; | |
| } | |
| } | |
| public void writeEndDocument() | |
| throws XMLStreamException | |
| { | |
| while (!elements.isEmpty()) | |
| writeEndElement(); | |
| } | |
| public void close() | |
| throws XMLStreamException | |
| { | |
| flush(); | |
| } | |
| public void flush() | |
| throws XMLStreamException | |
| { | |
| try | |
| { | |
| writer.flush(); | |
| } | |
| catch (IOException e) | |
| { | |
| XMLStreamException e2 = new XMLStreamException(e); | |
| e2.initCause(e); | |
| throw e2; | |
| } | |
| } | |
| public void writeAttribute(String localName, String value) | |
| throws XMLStreamException | |
| { | |
| if (!inStartElement) | |
| throw new IllegalStateException(); | |
| try | |
| { | |
| if (!isName(localName)) | |
| throw new IllegalArgumentException("illegal Name: " + localName); | |
| if (!isChars(value)) | |
| throw new IllegalArgumentException("illegal character: " + value); | |
| writer.write(' '); | |
| writer.write(localName); | |
| writer.write('='); | |
| writer.write('"'); | |
| if (hasXML11RestrictedChars) | |
| writeEncodedWithRestrictedChars(value, true); | |
| else | |
| writeEncoded(value, true); | |
| writer.write('"'); | |
| } | |
| catch (IOException e) | |
| { | |
| XMLStreamException e2 = new XMLStreamException(e); | |
| e2.initCause(e); | |
| throw e2; | |
| } | |
| } | |
| public void writeAttribute(String prefix, String namespaceURI, | |
| String localName, String value) | |
| throws XMLStreamException | |
| { | |
| if (!inStartElement) | |
| throw new IllegalStateException(); | |
| try | |
| { | |
| if (namespaceURI != null && !isURI(namespaceURI)) | |
| throw new IllegalArgumentException("illegal URI: " + namespaceURI); | |
| if (prefix != null && !isNCName(prefix)) | |
| throw new IllegalArgumentException("illegal NCName: " + prefix); | |
| if (!isNCName(localName)) | |
| throw new IllegalArgumentException("illegal NCName: " + localName); | |
| if (!isChars(value)) | |
| throw new IllegalArgumentException("illegal character: " + value); | |
| String currentPrefix = getPrefix(namespaceURI); | |
| if (currentPrefix == null) | |
| { | |
| if (prefixDefaulting) | |
| writeNamespaceImpl(prefix, namespaceURI); | |
| else | |
| throw new XMLStreamException("namespace " + namespaceURI + | |
| " is not bound"); | |
| } | |
| else if (!currentPrefix.equals(prefix)) | |
| throw new XMLStreamException("namespace " + namespaceURI + | |
| " is bound to prefix " + | |
| currentPrefix); | |
| writer.write(' '); | |
| if (!"".equals(prefix)) | |
| { | |
| writer.write(prefix); | |
| writer.write(':'); | |
| } | |
| writer.write(localName); | |
| writer.write('='); | |
| writer.write('"'); | |
| if (hasXML11RestrictedChars) | |
| writeEncodedWithRestrictedChars(value, true); | |
| else | |
| writeEncoded(value, true); | |
| writer.write('"'); | |
| } | |
| catch (IOException e) | |
| { | |
| XMLStreamException e2 = new XMLStreamException(e); | |
| e2.initCause(e); | |
| throw e2; | |
| } | |
| } | |
| public void writeAttribute(String namespaceURI, String localName, | |
| String value) | |
| throws XMLStreamException | |
| { | |
| if (!inStartElement) | |
| throw new IllegalStateException(); | |
| try | |
| { | |
| if (namespaceURI != null && !isURI(namespaceURI)) | |
| throw new IllegalArgumentException("illegal URI: " + namespaceURI); | |
| if (!isName(localName)) | |
| throw new IllegalArgumentException("illegal Name: " + localName); | |
| if (!isChars(value)) | |
| throw new IllegalArgumentException("illegal character: " + value); | |
| String prefix = getPrefix(namespaceURI); | |
| if (prefix == null) | |
| { | |
| if (prefixDefaulting) | |
| { | |
| prefix = XMLConstants.DEFAULT_NS_PREFIX; | |
| writeNamespaceImpl(prefix, namespaceURI); | |
| } | |
| else | |
| throw new XMLStreamException("namespace " + namespaceURI + | |
| " is not bound"); | |
| } | |
| writer.write(' '); | |
| if (!"".equals(prefix)) | |
| { | |
| writer.write(prefix); | |
| writer.write(':'); | |
| } | |
| writer.write(localName); | |
| writer.write('='); | |
| writer.write('"'); | |
| if (hasXML11RestrictedChars) | |
| writeEncodedWithRestrictedChars(value, true); | |
| else | |
| writeEncoded(value, true); | |
| writer.write('"'); | |
| } | |
| catch (IOException e) | |
| { | |
| XMLStreamException e2 = new XMLStreamException(e); | |
| e2.initCause(e); | |
| throw e2; | |
| } | |
| } | |
| public void writeNamespace(String prefix, String namespaceURI) | |
| throws XMLStreamException | |
| { | |
| if (!inStartElement) | |
| throw new IllegalStateException(); | |
| try | |
| { | |
| if (!isURI(namespaceURI)) | |
| throw new IllegalArgumentException("illegal URI: " + namespaceURI); | |
| if (!isNCName(prefix)) | |
| throw new IllegalArgumentException("illegal NCName: " + prefix); | |
| } | |
| catch (IOException e) | |
| { | |
| XMLStreamException e2 = new XMLStreamException(e); | |
| e2.initCause(e); | |
| throw e2; | |
| } | |
| writeNamespaceImpl(prefix, namespaceURI); | |
| } | |
| private void writeNamespaceImpl(String prefix, String namespaceURI) | |
| throws XMLStreamException | |
| { | |
| try | |
| { | |
| if (prefix == null) | |
| prefix = XMLConstants.DEFAULT_NS_PREFIX; | |
| setPrefix(prefix, namespaceURI); | |
| writer.write(' '); | |
| writer.write("xmlns"); | |
| if (!XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) | |
| { | |
| writer.write(':'); | |
| writer.write(prefix); | |
| } | |
| writer.write('='); | |
| writer.write('"'); | |
| writer.write(namespaceURI); | |
| writer.write('"'); | |
| } | |
| catch (IOException e) | |
| { | |
| XMLStreamException e2 = new XMLStreamException(e); | |
| e2.initCause(e); | |
| throw e2; | |
| } | |
| } | |
| public void writeDefaultNamespace(String namespaceURI) | |
| throws XMLStreamException | |
| { | |
| if (!inStartElement) | |
| throw new IllegalStateException(); | |
| if (!isURI(namespaceURI)) | |
| throw new IllegalArgumentException("illegal URI: " + namespaceURI); | |
| writeNamespaceImpl(XMLConstants.DEFAULT_NS_PREFIX, namespaceURI); | |
| } | |
| public void writeComment(String data) | |
| throws XMLStreamException | |
| { | |
| if (data == null) | |
| return; | |
| try | |
| { | |
| if (!isChars(data)) | |
| throw new IllegalArgumentException("illegal XML character: " + data); | |
| if (data.indexOf("--") != -1) | |
| throw new IllegalArgumentException("illegal comment: " + data); | |
| endStartElement(); | |
| writer.write("<!--"); | |
| if (hasXML11RestrictedChars) | |
| { | |
| int[] seq = UnicodeReader.toCodePointArray(data); | |
| for (int i = 0; i < seq.length; i++) | |
| { | |
| int c = seq[i]; | |
| if (XMLParser.isXML11RestrictedChar(c)) | |
| writer.write("&#x" + Integer.toHexString(c) + ";"); | |
| else | |
| writer.write(Character.toChars(i)); | |
| } | |
| } | |
| else | |
| writer.write(data); | |
| writer.write("-->"); | |
| } | |
| catch (IOException e) | |
| { | |
| XMLStreamException e2 = new XMLStreamException(e); | |
| e2.initCause(e); | |
| throw e2; | |
| } | |
| } | |
| public void writeProcessingInstruction(String target) | |
| throws XMLStreamException | |
| { | |
| writeProcessingInstruction(target, null); | |
| } | |
| public void writeProcessingInstruction(String target, String data) | |
| throws XMLStreamException | |
| { | |
| try | |
| { | |
| if (!isName(target) || "xml".equalsIgnoreCase(target)) | |
| throw new IllegalArgumentException("illegal PITarget: " + target); | |
| if (data != null && !isChars(data)) | |
| throw new IllegalArgumentException("illegal XML character: " + data); | |
| endStartElement(); | |
| writer.write('<'); | |
| writer.write('?'); | |
| writer.write(target); | |
| if (data != null) | |
| { | |
| writer.write(' '); | |
| if (hasXML11RestrictedChars) | |
| { | |
| int[] seq = UnicodeReader.toCodePointArray(data); | |
| for (int i = 0; i < seq.length; i++) | |
| { | |
| int c = seq[i]; | |
| if (XMLParser.isXML11RestrictedChar(c)) | |
| writer.write("&#x" + Integer.toHexString(c) + ";"); | |
| else | |
| writer.write(Character.toChars(i)); | |
| } | |
| } | |
| else | |
| writer.write(data); | |
| } | |
| writer.write('?'); | |
| writer.write('>'); | |
| } | |
| catch (IOException e) | |
| { | |
| XMLStreamException e2 = new XMLStreamException(e); | |
| e2.initCause(e); | |
| throw e2; | |
| } | |
| } | |
| public void writeCData(String data) | |
| throws XMLStreamException | |
| { | |
| try | |
| { | |
| if (!isChars(data) || hasXML11RestrictedChars) | |
| throw new IllegalArgumentException("illegal XML character: " + data); | |
| if (data.indexOf("]]") != -1) | |
| throw new IllegalArgumentException("illegal CDATA section: " + data); | |
| endStartElement(); | |
| writer.write("<![CDATA["); | |
| writer.write(data); | |
| writer.write("]]>"); | |
| } | |
| catch (IOException e) | |
| { | |
| XMLStreamException e2 = new XMLStreamException(e); | |
| e2.initCause(e); | |
| throw e2; | |
| } | |
| } | |
| public void writeDTD(String dtd) | |
| throws XMLStreamException | |
| { | |
| // Really thoroughly pointless method... | |
| try | |
| { | |
| if (!isName(dtd)) | |
| throw new IllegalArgumentException("illegal Name: " + dtd); | |
| writer.write("<!DOCTYPE "); | |
| writer.write(dtd); | |
| writer.write('>'); | |
| } | |
| catch (IOException e) | |
| { | |
| XMLStreamException e2 = new XMLStreamException(e); | |
| e2.initCause(e); | |
| throw e2; | |
| } | |
| } | |
| public void writeEntityRef(String name) | |
| throws XMLStreamException | |
| { | |
| try | |
| { | |
| if (!isName(name)) | |
| throw new IllegalArgumentException("illegal Name: " + name); | |
| endStartElement(); | |
| writer.write('&'); | |
| writer.write(name); | |
| writer.write(';'); | |
| } | |
| catch (IOException e) | |
| { | |
| XMLStreamException e2 = new XMLStreamException(e); | |
| e2.initCause(e); | |
| throw e2; | |
| } | |
| } | |
| public void writeStartDocument() | |
| throws XMLStreamException | |
| { | |
| writeStartDocument(null, null); | |
| } | |
| public void writeStartDocument(String version) | |
| throws XMLStreamException | |
| { | |
| writeStartDocument(null, version); | |
| } | |
| public void writeStartDocument(String encoding, String version) | |
| throws XMLStreamException | |
| { | |
| if (version == null) | |
| version = "1.0"; | |
| else if ("1.1".equals(version)) | |
| xml11 = true; | |
| encoding = this.encoding; // YES: the parameter must be ignored | |
| if (encoding == null) | |
| encoding = "UTF-8"; | |
| if (!"1.0".equals(version) && !"1.1".equals(version)) | |
| throw new IllegalArgumentException(version); | |
| try | |
| { | |
| writer.write("<?xml version=\""); | |
| writer.write(version); | |
| writer.write("\" encoding=\""); | |
| writer.write(encoding); | |
| writer.write("\"?>"); | |
| writer.write(System.getProperty("line.separator")); | |
| } | |
| catch (IOException e) | |
| { | |
| XMLStreamException e2 = new XMLStreamException(e); | |
| e2.initCause(e); | |
| throw e2; | |
| } | |
| } | |
| public void writeCharacters(String text) | |
| throws XMLStreamException | |
| { | |
| if (text == null) | |
| return; | |
| try | |
| { | |
| if (!isChars(text)) | |
| throw new IllegalArgumentException("illegal XML character: " + text); | |
| endStartElement(); | |
| if (hasXML11RestrictedChars) | |
| writeEncodedWithRestrictedChars(text, false); | |
| else | |
| writeEncoded(text, false); | |
| } | |
| catch (IOException e) | |
| { | |
| XMLStreamException e2 = new XMLStreamException(e); | |
| e2.initCause(e); | |
| throw e2; | |
| } | |
| } | |
| public void writeCharacters(char[] text, int start, int len) | |
| throws XMLStreamException | |
| { | |
| writeCharacters(new String(text, start, len)); | |
| } | |
| public String getPrefix(String uri) | |
| throws XMLStreamException | |
| { | |
| String prefix = namespaces.getPrefix(uri); | |
| if (prefix == null && namespaceContext != null) | |
| prefix = namespaceContext.getPrefix(uri); | |
| return prefix; | |
| } | |
| public void setPrefix(String prefix, String uri) | |
| throws XMLStreamException | |
| { | |
| try | |
| { | |
| if (!isURI(uri)) | |
| throw new IllegalArgumentException("illegal URI: " + uri); | |
| if (!isNCName(prefix)) | |
| throw new IllegalArgumentException("illegal NCName: " + prefix); | |
| } | |
| catch (IOException e) | |
| { | |
| XMLStreamException e2 = new XMLStreamException(e); | |
| e2.initCause(e); | |
| throw e2; | |
| } | |
| if (!namespaces.declarePrefix(prefix, uri)) | |
| throw new XMLStreamException("illegal prefix " + prefix); | |
| } | |
| public void setDefaultNamespace(String uri) | |
| throws XMLStreamException | |
| { | |
| if (!isURI(uri)) | |
| throw new IllegalArgumentException("illegal URI: " + uri); | |
| if (!namespaces.declarePrefix(XMLConstants.DEFAULT_NS_PREFIX, uri)) | |
| throw new XMLStreamException("illegal default namespace prefix"); | |
| } | |
| public void setNamespaceContext(NamespaceContext context) | |
| throws XMLStreamException | |
| { | |
| namespaceContext = context; | |
| } | |
| public NamespaceContext getNamespaceContext() | |
| { | |
| return namespaceContext; | |
| } | |
| public Object getProperty(String name) | |
| throws IllegalArgumentException | |
| { | |
| throw new IllegalArgumentException(name); | |
| } | |
| /** | |
| * Write the specified text, ensuring that the content is suitably encoded | |
| * for XML. | |
| * @param text the text to write | |
| * @param inAttr whether we are in an attribute value | |
| */ | |
| private void writeEncoded(String text, boolean inAttr) | |
| throws IOException | |
| { | |
| char[] chars = text.toCharArray(); | |
| int start = 0; | |
| int end = chars.length; | |
| int len = 0; | |
| for (int i = start; i < end; i++) | |
| { | |
| char c = chars[i]; | |
| if (c == '<' || c == '>' || c == '&') | |
| { | |
| writer.write(chars, start, len); | |
| if (c == '<') | |
| writer.write("<"); | |
| else if (c == '>') | |
| writer.write(">"); | |
| else | |
| writer.write("&"); | |
| start = i + 1; | |
| len = 0; | |
| } | |
| else if (inAttr && (c == '"' || c == '\'')) | |
| { | |
| writer.write(chars, start, len); | |
| if (c == '"') | |
| writer.write("""); | |
| else | |
| writer.write("'"); | |
| start = i + 1; | |
| len = 0; | |
| } | |
| else | |
| len++; | |
| } | |
| if (len > 0) | |
| writer.write(chars, start, len); | |
| } | |
| /** | |
| * Writes the specified text, in the knowledge that some of the | |
| * characters are XML 1.1 restricted characters. | |
| */ | |
| private void writeEncodedWithRestrictedChars(String text, boolean inAttr) | |
| throws IOException | |
| { | |
| int[] seq = UnicodeReader.toCodePointArray(text); | |
| for (int i = 0; i < seq.length; i++) | |
| { | |
| int c = seq[i]; | |
| switch (c) | |
| { | |
| case 0x3c: // '<' | |
| writer.write("<"); | |
| break; | |
| case 0x3e: // '>' | |
| writer.write(">"); | |
| break; | |
| case 0x26: // '&' | |
| writer.write("&"); | |
| break; | |
| case 0x22: // '"' | |
| if (inAttr) | |
| writer.write("""); | |
| else | |
| writer.write(c); | |
| break; | |
| case 0x27: // '\'' | |
| if (inAttr) | |
| writer.write("'"); | |
| else | |
| writer.write(c); | |
| break; | |
| default: | |
| if (XMLParser.isXML11RestrictedChar(c)) | |
| writer.write("&#x" + Integer.toHexString(c) + ";"); | |
| else | |
| { | |
| char[] chars = Character.toChars(c); | |
| writer.write(chars, 0, chars.length); | |
| } | |
| } | |
| } | |
| } | |
| private boolean isName(String text) | |
| throws IOException | |
| { | |
| if (text == null) | |
| return false; | |
| int[] seq = UnicodeReader.toCodePointArray(text); | |
| if (seq.length < 1) | |
| return false; | |
| if (!XMLParser.isNameStartCharacter(seq[0], xml11)) | |
| return false; | |
| for (int i = 1; i < seq.length; i++) | |
| { | |
| if (!XMLParser.isNameCharacter(seq[i], xml11)) | |
| return false; | |
| } | |
| return true; | |
| } | |
| private boolean isNCName(String text) | |
| throws IOException | |
| { | |
| if (text == null) | |
| return false; | |
| int[] seq = UnicodeReader.toCodePointArray(text); | |
| if (seq.length < 1) | |
| return false; | |
| if (!XMLParser.isNameStartCharacter(seq[0], xml11) || seq[0] == 0x3a) | |
| return false; | |
| for (int i = 1; i < seq.length; i++) | |
| { | |
| if (!XMLParser.isNameCharacter(seq[i], xml11) || seq[i] == 0x3a) | |
| return false; | |
| } | |
| return true; | |
| } | |
| private boolean isChars(String text) | |
| throws IOException | |
| { | |
| if (text == null) | |
| return false; | |
| int[] seq = UnicodeReader.toCodePointArray(text); | |
| hasXML11RestrictedChars = false; | |
| if (xml11) | |
| { | |
| for (int i = 0; i < seq.length; i++) | |
| { | |
| if (!XMLParser.isXML11Char(seq[i])) | |
| return false; | |
| if (XMLParser.isXML11RestrictedChar(seq[i])) | |
| hasXML11RestrictedChars = true; | |
| } | |
| } | |
| else | |
| { | |
| for (int i = 0; i < seq.length; i++) | |
| { | |
| if (!XMLParser.isChar(seq[i])) | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| private boolean isURI(String text) | |
| { | |
| if (text == null) | |
| return false; | |
| char[] chars = text.toCharArray(); | |
| if (chars.length < 1) | |
| return false; | |
| for (int i = 0; i < chars.length; i++) | |
| { | |
| if (chars[i] < 0x20 || chars[i] >= 0x7f) | |
| return false; | |
| } | |
| return true; | |
| } | |
| } | |