| /* 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; |
| } |
| |
| } |
| |