123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550 |
- /* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE. */
-
- package org.kxml2.io;
- import java.io.*;
- import org.xmlpull.v1.*;
- public class KXmlSerializer implements IXmlSerializer {
- // static final String UNDEFINED = ":";
- private Writer writer;
- private boolean pending;
- private int auto;
- private int depth;
- private String[] elementStack = new String[12];
- //nsp/prefix/name
- private int[] nspCounts = new int[4];
- private String[] nspStack = new String[8];
- //prefix/nsp; both empty are ""
- private boolean[] indent = new boolean[4];
- private boolean unicode;
- private String encoding;
- private final void check(boolean close) throws IOException {
- if (!pending)
- return;
- depth++;
- pending = false;
- if (indent.length <= depth) {
- boolean[] hlp = new boolean[depth + 4];
- System.arraycopy(indent, 0, hlp, 0, depth);
- indent = hlp;
- }
- indent[depth] = indent[depth - 1];
- for (int i = nspCounts[depth - 1];
- i < nspCounts[depth];
- i++) {
- writer.write(' ');
- writer.write("xmlns");
- if (!"".equals(nspStack[i * 2])) {
- writer.write(':');
- writer.write(nspStack[i * 2]);
- }
- else if ("".equals(getNamespace()) && !"".equals(nspStack[i * 2 + 1]))
- throw new IllegalStateException("Cannot set default namespace for elements in no namespace");
- writer.write("=\"");
- writeEscaped(nspStack[i * 2 + 1], '"');
- writer.write('"');
- }
- if (nspCounts.length <= depth + 1) {
- int[] hlp = new int[depth + 8];
- System.arraycopy(nspCounts, 0, hlp, 0, depth + 1);
- nspCounts = hlp;
- }
- nspCounts[depth + 1] = nspCounts[depth];
- // nspCounts[depth + 2] = nspCounts[depth];
- writer.write(close ? " />" : ">");
- }
- private final void writeEscaped(String s, int quot)
- throws IOException {
- for (int i = 0; i < s.length(); i++) {
- char c = s.charAt(i);
- switch (c) {
- case '\n':
- case '\r':
- case '\t':
- if(quot == -1)
- writer.write(c);
- else
- writer.write("&#"+((int) c)+';');
- break;
- case '&' :
- writer.write("&");
- break;
- case '>' :
- writer.write(">");
- break;
- case '<' :
- writer.write("<");
- break;
- case '"' :
- case '\'' :
- if (c == quot) {
- writer.write(
- c == '"' ? """ : "'");
- break;
- }
- default :
- //if(c < ' ')
- // throw new IllegalArgumentException("Illegal control code:"+((int) c));
- // MH why is @ serialized as &# ???
- //if (c >= ' ' && c !='@' && (c < 127 || unicode))
- if (c >= ' ' && (c < 127 || unicode))
- writer.write(c);
- else
- writer.write("&#" + ((int) c) + ";");
- }
- }
- }
- /*
- private final void writeIndent() throws IOException {
- writer.write("\r\n");
- for (int i = 0; i < depth; i++)
- writer.write(' ');
- }*/
- public void docdecl(String dd) throws IOException {
- writer.write("<!DOCTYPE");
- writer.write(dd);
- writer.write(">");
- }
- public void endDocument() throws IOException {
- while (depth > 0) {
- endTag(
- elementStack[depth * 3 - 3],
- elementStack[depth * 3 - 1]);
- }
- flush();
- }
- public void entityRef(String name) throws IOException {
- check(false);
- writer.write('&');
- writer.write(name);
- writer.write(';');
- }
- public boolean getFeature(String name) {
- //return false;
- return (
- "http://xmlpull.org/v1/doc/features.html#indent-output"
- .equals(
- name))
- ? indent[depth]
- : false;
- }
- public String getPrefix(String namespace, boolean create) {
- try {
- return getPrefix(namespace, false, create);
- }
- catch (IOException e) {
- throw new RuntimeException(e.toString());
- }
- }
- private final String getPrefix(
- String namespace,
- boolean includeDefault,
- boolean create)
- throws IOException {
- for (int i = nspCounts[depth + 1] * 2 - 2;
- i >= 0;
- i -= 2) {
- if (nspStack[i + 1].equals(namespace)
- && (includeDefault || !nspStack[i].equals(""))) {
- String cand = nspStack[i];
- for (int j = i + 2;
- j < nspCounts[depth + 1] * 2;
- j++) {
- if (nspStack[j].equals(cand)) {
- cand = null;
- break;
- }
- }
- if (cand != null)
- return cand;
- }
- }
- if (!create)
- return null;
- String prefix;
- if ("".equals(namespace))
- prefix = "";
- else {
- do {
- prefix = "n" + (auto++);
- for (int i = nspCounts[depth + 1] * 2 - 2;
- i >= 0;
- i -= 2) {
- if (prefix.equals(nspStack[i])) {
- prefix = null;
- break;
- }
- }
- }
- while (prefix == null);
- }
- boolean p = pending;
- pending = false;
- setPrefix(prefix, namespace);
- pending = p;
- return prefix;
- }
- public Object getProperty(String name) {
- throw new RuntimeException("Unsupported property");
- }
- public void ignorableWhitespace(String s)
- throws IOException {
- text(s);
- }
- public void setFeature(String name, boolean value) {
- if ("http://xmlpull.org/v1/doc/features.html#indent-output"
- .equals(name)) {
- indent[depth] = value;
- }
- else
- throw new RuntimeException("Unsupported Feature");
- }
- public void setProperty(String name, Object value) {
- throw new RuntimeException(
- "Unsupported Property:" + value);
- }
- public void setPrefix(String prefix, String namespace)
- throws IOException {
- check(false);
- if (prefix == null)
- prefix = "";
- if (namespace == null)
- namespace = "";
- String defined = getPrefix(namespace, true, false);
- // boil out if already defined
- if (prefix.equals(defined))
- return;
- int pos = (nspCounts[depth + 1]++) << 1;
- if (nspStack.length < pos + 1) {
- String[] hlp = new String[nspStack.length + 16];
- System.arraycopy(nspStack, 0, hlp, 0, pos);
- nspStack = hlp;
- }
- nspStack[pos++] = prefix;
- nspStack[pos] = namespace;
- }
- public void setOutput(Writer writer) {
- this.writer = writer;
- // elementStack = new String[12]; //nsp/prefix/name
- //nspCounts = new int[4];
- //nspStack = new String[8]; //prefix/nsp
- //indent = new boolean[4];
- nspCounts[0] = 2;
- nspCounts[1] = 2;
- nspStack[0] = "";
- nspStack[1] = "";
- nspStack[2] = "xml";
- nspStack[3] = "http://www.w3.org/XML/1998/namespace";
- pending = false;
- auto = 0;
- depth = 0;
- unicode = false;
- }
- public void setOutput(OutputStream os, String encoding)
- throws IOException {
- if (os == null)
- throw new IllegalArgumentException("kxml: os=null");
- setOutput(
- encoding == null
- ? new OutputStreamWriter(os)
- : new OutputStreamWriter(os, encoding));
- this.encoding = encoding;
- if (encoding != null
- && encoding.toLowerCase().startsWith("utf"))
- unicode = true;
- }
- public void startDocument(
- String encoding,
- Boolean standalone)
- throws IOException {
- writer.write("<?xml version='1.0' ");
- if (encoding != null) {
- this.encoding = encoding;
- if (encoding.toLowerCase().startsWith("utf"))
- unicode = true;
- }
- if (this.encoding != null) {
- writer.write("encoding='");
- writer.write(this.encoding);
- writer.write("' ");
- }
- if (standalone != null) {
- writer.write("standalone='");
- writer.write(
- standalone.booleanValue() ? "yes" : "no");
- writer.write("' ");
- }
- writer.write("?>");
- }
- public IXmlSerializer startTag(String namespace, String name)
- throws IOException {
- check(false);
- // if (namespace == null)
- // namespace = "";
- if (indent[depth]) {
- writer.write("\r\n");
- for (int i = 0; i < depth; i++)
- writer.write(" ");
- }
- int esp = depth * 3;
- if (elementStack.length < esp + 3) {
- String[] hlp = new String[elementStack.length + 12];
- System.arraycopy(elementStack, 0, hlp, 0, esp);
- elementStack = hlp;
- }
- String prefix =
- namespace == null
- ? ""
- : getPrefix(namespace, true, true);
- if ("".equals(namespace)) {
- for (int i = nspCounts[depth];
- i < nspCounts[depth + 1];
- i++) {
- if ("".equals(nspStack[i * 2]) && !"".equals(nspStack[i * 2 + 1])) {
- throw new IllegalStateException("Cannot set default namespace for elements in no namespace");
- }
- }
- }
- elementStack[esp++] = namespace;
- elementStack[esp++] = prefix;
- elementStack[esp] = name;
- writer.write('<');
- if (!"".equals(prefix)) {
- writer.write(prefix);
- writer.write(':');
- }
- writer.write(name);
- pending = true;
- return this;
- }
- public IXmlSerializer attribute(
- String namespace,
- String name,
- String value)
- throws IOException {
- if (!pending)
- throw new IllegalStateException("illegal position for attribute");
- // int cnt = nspCounts[depth];
- if (namespace == null)
- namespace = "";
- // depth--;
- // pending = false;
- String prefix =
- "".equals(namespace)
- ? ""
- : getPrefix(namespace, false, true);
- // pending = true;
- // depth++;
- /* if (cnt != nspCounts[depth]) {
- writer.write(' ');
- writer.write("xmlns");
- if (nspStack[cnt * 2] != null) {
- writer.write(':');
- writer.write(nspStack[cnt * 2]);
- }
- writer.write("=\"");
- writeEscaped(nspStack[cnt * 2 + 1], '"');
- writer.write('"');
- }
- */
- writer.write(' ');
- if (!"".equals(prefix)) {
- writer.write(prefix);
- writer.write(':');
- }
- writer.write(name);
- writer.write('=');
- char q = value.indexOf('"') == -1 ? '"' : '\'';
- writer.write(q);
- writeEscaped(value, q);
- writer.write(q);
- return this;
- }
- public void flush() throws IOException {
- check(false);
- writer.flush();
- }
- /*
- public void close() throws IOException {
- check();
- writer.close();
- }
- */
- public IXmlSerializer endTag(String namespace, String name)
- throws IOException {
- if (!pending)
- depth--;
- // if (namespace == null)
- // namespace = "";
- if ((namespace == null
- && elementStack[depth * 3] != null)
- || (namespace != null
- && !namespace.equals(elementStack[depth * 3]))
- || !elementStack[depth * 3 + 2].equals(name))
- throw new IllegalArgumentException("</{"+namespace+"}"+name+"> does not match start");
- if (pending) {
- check(true);
- depth--;
- }
- else {
- if (indent[depth + 1]) {
- writer.write("\r\n");
- for (int i = 0; i < depth; i++)
- writer.write(" ");
- }
- writer.write("</");
- String prefix = elementStack[depth * 3 + 1];
- if (!"".equals(prefix)) {
- writer.write(prefix);
- writer.write(':');
- }
- writer.write(name);
- writer.write('>');
- }
- nspCounts[depth + 1] = nspCounts[depth];
- return this;
- }
- public String getNamespace() {
- return getDepth() == 0 ? null : elementStack[getDepth() * 3 - 3];
- }
- public String getName() {
- return getDepth() == 0 ? null : elementStack[getDepth() * 3 - 1];
- }
- public int getDepth() {
- return pending ? depth + 1 : depth;
- }
- public IXmlSerializer text(String text) throws IOException {
- check(false);
- indent[depth] = false;
- writeEscaped(text, -1);
- return this;
- }
- public IXmlSerializer text(char[] text, int start, int len)
- throws IOException {
- text(new String(text, start, len));
- return this;
- }
- public void cdsect(String data) throws IOException {
- check(false);
- writer.write("<![CDATA[");
- writer.write(data);
- writer.write("]]>");
- }
- public void comment(String comment) throws IOException {
- check(false);
- writer.write("<!--");
- writer.write(comment);
- writer.write("-->");
- }
- public void processingInstruction(String pi)
- throws IOException {
- check(false);
- writer.write("<?");
- writer.write(pi);
- writer.write("?>");
- }
- }
|