Servlet listener.
+ * This class creates and destroys servlet contexts. * * @author BaseX Team 2005-15, BSD License * @author Christian Gruen */ -@WebListener public final class ServletListener implements ServletContextListener { @Override public void contextInitialized(final ServletContextEvent event) { diff -Nru basex-8.1.1/basex-api/src/main/java/org/basex/http/SessionListener.java basex-8.2.3/basex-api/src/main/java/org/basex/http/SessionListener.java --- basex-8.1.1/basex-api/src/main/java/org/basex/http/SessionListener.java 2015-04-16 13:52:47.000000000 +0000 +++ basex-8.2.3/basex-api/src/main/java/org/basex/http/SessionListener.java 2015-07-14 10:54:40.000000000 +0000 @@ -5,7 +5,7 @@ import javax.servlet.http.*; /** - * This class bundles context-based information on a single HTTP operation. + * This class creates and destroys HTTP sessions. * * @author BaseX Team 2005-15, BSD License * @author Christian Gruen diff -Nru basex-8.1.1/basex-api/src/main/java/org/basex/http/webdav/impl/WebDAVService.java basex-8.2.3/basex-api/src/main/java/org/basex/http/webdav/impl/WebDAVService.java --- basex-8.1.1/basex-api/src/main/java/org/basex/http/webdav/impl/WebDAVService.java 2015-04-16 13:52:47.000000000 +0000 +++ basex-8.2.3/basex-api/src/main/java/org/basex/http/webdav/impl/WebDAVService.java 2015-07-14 10:54:40.000000000 +0000 @@ -4,7 +4,6 @@ import static org.basex.query.func.Function.*; import java.io.*; -import java.text.*; import java.util.*; import java.util.Map.Entry; import java.util.List; @@ -114,14 +113,7 @@ public long timestamp(final String db) throws IOException { final WebDAVQuery query = new WebDAVQuery(DATA.args(_DB_INFO.args("$path") + "/descendant::" + DbFn.toName(Text.TIMESTAMP) + "[1]")).bind("path", db); - - try { - // retrieve and parse timestamp - return DateTime.parse(execute(query).get(0), DateTime.DATETIME).getTime(); - } catch(final ParseException ex) { - Util.errln(ex); - return 0L; - } + return DateTime.parse(execute(query).get(0)).getTime(); } /** @@ -146,7 +138,7 @@ final StringList result = execute(query); final boolean raw = Boolean.parseBoolean(result.get(0)); final MediaType type = new MediaType(result.get(1)); - final long mod = DateTime.parse(result.get(2)); + final long mod = DateTime.parse(result.get(2)).getTime(); final Long size = raw ? Long.valueOf(result.get(3)) : null; final String pth = stripLeadingSlash(result.get(4)); return new ResourceMetaData(db, pth, mod, raw, type, size); @@ -320,7 +312,7 @@ for(int r = 0; r < rs; r += 5) { final boolean raw = Boolean.parseBoolean(result.get(r)); final MediaType ctype = new MediaType(result.get(r + 1)); - final long mod = DateTime.parse(result.get(r + 2)); + final long mod = DateTime.parse(result.get(r + 2)).getTime(); final Long size = raw ? Long.valueOf(result.get(r + 3)) : null; final String pth = stripLeadingSlash(result.get(r + 4)); final int ix = pth.indexOf(SEP); @@ -351,7 +343,7 @@ final List{ $cons:DBA-DIR }
.
+ - - |
+
+
+
+ |
+
A container/list for atomic updates. Updates must be added from the lowest to - * the highest PRE value (regarding the location of the update). Updates are finally - * applied by this container from the highest to the lowest PRE value (reverse document - * order) to support efficient structural bulk updates etc.
- * - *If a collection of updates is carried out via the AUC there are several - * benefits:
- * - *To avoid ambiguity it is not allowed to add:
- *Updates are added in a streaming fashion where the most recently added update is - * remembered. This avoids additional traversals of the AUC during consistency checks and - * further optimizations.
- * - * @author BaseX Team 2005-15, BSD License - * @author Lukas Kircher - */ -public final class AtomicUpdateCache { - /** List of structural updates (nodes are inserted to / deleted from the table. */ - private final ListThis class converts a JSON document to XML.
+ * + * @author BaseX Team 2005-15, BSD License + * @author Christian Gruen + */ +public final class JsonBasicConverter extends JsonXmlConverter { + /** Add pairs. */ + private final BoolList addPairs = new BoolList(); + /** Unescape characters. */ + private final boolean unescape; + /** Name of next element. */ + private byte[] name; + + /** + * Constructor. + * @param opts json options + * @throws QueryIOException query I/O exception + */ + JsonBasicConverter(final JsonParserOptions opts) throws QueryIOException { + super(opts); + unescape = jopts.get(JsonParserOptions.UNESCAPE); + addPairs.add(true); + final JsonDuplicates dupl = jopts.get(JsonParserOptions.DUPLICATES); + if(dupl == JsonDuplicates.USE_LAST) throw new QueryIOException( + BXJS_INVALID_X.get(null, JsonParserOptions.DUPLICATES.name(), dupl)); + } + + @Override + void openObject() { + open(MAP); + } + + @Override + void openPair(final byte[] key, final boolean add) { + name = key; + addPairs.add(add() && add); + } + + @Override + void closePair(final boolean add) { + addPairs.pop(); + } + + @Override + void closeObject() { + close(); + } + + @Override + void openArray() { + open(ARRAY); + } + + @Override + void openItem() { } + + @Override + void closeItem() { } + + @Override + void closeArray() { + close(); + } + + @Override + public void numberLit(final byte[] value) { + if(add()) addElem(NUMBER).add(value); + } + + @Override + public void stringLit(final byte[] value) { + if(add()) { + final FElem e = addElem(STRING).add(value); + if(!unescape && contains(value, '\\')) e.add(ESCAPED, TRUE); + } + } + + @Override + public void nullLit() { + if(add()) addElem(NULL); + } + + @Override + public void booleanLit(final byte[] value) { + if(add()) addElem(BOOLEAN).add(value); + } + + /** + * Adds a new element with the given type. + * @param type JSON type + * @return new element + */ + private FElem addElem(final byte[] type) { + final FElem e = new FElem(type, QueryText.FN_URI); + // root node: declare namespace + if(curr == null) e.declareNS(); + + if(name != null) { + e.add(KEY, name); + if(!unescape && contains(name, '\\')) e.add(ESCAPED_KEY, TRUE); + name = null; + } + + if(curr != null) curr.add(e); + else curr = e; + return e; + } + + /** + * Opens an entry. + * @param type JSON type + */ + private void open(final byte[] type) { + if(add()) curr = addElem(type); + } + + /** + * Closes an entry. + */ + private void close() { + if(add()) { + final FElem par = (FElem) curr.parent(); + if(par != null) curr = par; + } + } + + /** + * Indicates if an entry should be added. + * @return result of check + */ + private boolean add() { + return addPairs.peek(); + } +} diff -Nru basex-8.1.1/basex-core/src/main/java/org/basex/io/parse/json/JsonConstants.java basex-8.2.3/basex-core/src/main/java/org/basex/io/parse/json/JsonConstants.java --- basex-8.1.1/basex-core/src/main/java/org/basex/io/parse/json/JsonConstants.java 2015-04-16 13:52:47.000000000 +0000 +++ basex-8.2.3/basex-core/src/main/java/org/basex/io/parse/json/JsonConstants.java 2015-07-14 10:54:40.000000000 +0000 @@ -15,6 +15,12 @@ byte[] TYPE = token("type"); /** Token: item. */ byte[] ITEM = token("item"); + /** Token: key. */ + byte[] KEY = token("key"); + /** Token: escaped. */ + byte[] ESCAPED = token("escaped"); + /** Token: escaped-key. */ + byte[] ESCAPED_KEY = token("escaped-key"); /** Token: string. */ byte[] STRING = token("string"); @@ -22,10 +28,16 @@ byte[] NUMBER = token("number"); /** Token: boolean. */ byte[] BOOLEAN = token("boolean"); + /** Token: null. */ + byte[] NULL = token("null"); /** Token: array. */ byte[] ARRAY = token("array"); /** Token: object. */ byte[] OBJECT = token("object"); + /** Token: map. */ + byte[] MAP = token("map"); + /** Allowed elements. */ + byte[][] ELEMENTS = { STRING, NUMBER, BOOLEAN, NULL, MAP }; /** Token: pair. */ byte[] PAIR = token("pair"); @@ -36,6 +48,8 @@ /** Supported data types. */ byte[][] TYPES = { OBJECT, ARRAY, STRING, NUMBER, BOOLEAN, NULL }; + /** Escape characters. */ + byte[] ESCAPES = token("\"\\/bfnrtu"); /** Plural. */ byte[] S = { 's' }; /** Global data type attributes. */ diff -Nru basex-8.1.1/basex-core/src/main/java/org/basex/io/parse/json/JsonConverter.java basex-8.2.3/basex-core/src/main/java/org/basex/io/parse/json/JsonConverter.java --- basex-8.1.1/basex-core/src/main/java/org/basex/io/parse/json/JsonConverter.java 2015-04-16 13:52:47.000000000 +0000 +++ basex-8.2.3/basex-core/src/main/java/org/basex/io/parse/json/JsonConverter.java 2015-07-14 10:54:40.000000000 +0000 @@ -66,12 +66,14 @@ * Returns a JSON converter for the given configuration. * @param jopts options * @return JSON converter + * @throws QueryIOException query I/O exception */ - public static JsonConverter get(final JsonParserOptions jopts) { + public static JsonConverter get(final JsonParserOptions jopts) throws QueryIOException { switch(jopts.get(JsonOptions.FORMAT)) { case JSONML: return new JsonMLConverter(jopts); case ATTRIBUTES: return new JsonAttsConverter(jopts); case MAP: return new JsonMapConverter(jopts); + case BASIC: return new JsonBasicConverter(jopts); default: return new JsonDirectConverter(jopts); } } @@ -85,9 +87,10 @@ /** * Called when a pair of a JSON object is opened. * @param key the key of the entry + * @param add add pair * @throws QueryIOException query exception */ - abstract void openPair(byte[] key) throws QueryIOException; + abstract void openPair(byte[] key, boolean add) throws QueryIOException; /** * Called when a pair of a JSON object is closed. @@ -125,30 +128,6 @@ abstract void closeArray() throws QueryIOException; /** - * Called when a constructor function is opened. - * @param name name of the constructor - * @throws QueryIOException query exception - */ - abstract void openConstr(byte[] name) throws QueryIOException; - - /** - * Called when an argument of a constructor function is opened. - */ - abstract void openArg(); - - /** - * Called when an argument of a constructor function is closed. - * @throws QueryIOException query exception - */ - abstract void closeArg() throws QueryIOException; - - /** - * Called when a constructor function is closed. - * @throws QueryIOException query exception - */ - abstract void closeConstr() throws QueryIOException; - - /** * Called when a number literal is encountered. * @param value string representation of the number literal * @throws QueryIOException query exception diff -Nru basex-8.1.1/basex-core/src/main/java/org/basex/io/parse/json/JsonDirectConverter.java basex-8.2.3/basex-core/src/main/java/org/basex/io/parse/json/JsonDirectConverter.java --- basex-8.1.1/basex-core/src/main/java/org/basex/io/parse/json/JsonDirectConverter.java 2015-04-16 13:52:47.000000000 +0000 +++ basex-8.2.3/basex-core/src/main/java/org/basex/io/parse/json/JsonDirectConverter.java 2015-07-14 10:54:40.000000000 +0000 @@ -1,7 +1,6 @@ package org.basex.io.parse.json; import static org.basex.io.parse.json.JsonConstants.*; -import static org.basex.util.Token.*; import org.basex.build.json.*; import org.basex.query.value.node.*; @@ -64,28 +63,13 @@ lax = jopts.get(JsonOptions.LAX); } - /** - * Adds a new element with the given type. - * @param type JSON type - * @return the element - */ - private FElem addElem(final byte[] type) { - final FElem e = new FElem(name); - addType(e, e.name(), type); - - if(curr != null) curr.add(e); - else curr = e; - name = null; - return e; - } - @Override void openObject() { curr = addElem(OBJECT); } @Override - void openPair(final byte[] key) { + void openPair(final byte[] key, final boolean add) { name = XMLToken.encode(key, lax); } @@ -117,31 +101,6 @@ } @Override - public void openConstr(final byte[] nm) { - // [LW] what can be done here? - openObject(); - openPair(nm); - openArray(); - } - - @Override - public void openArg() { - openItem(); - } - - @Override - public void closeArg() { - closeItem(); - } - - @Override - public void closeConstr() { - closeArray(); - closePair(true); - closeObject(); - } - - @Override public void numberLit(final byte[] value) { addElem(NUMBER).add(value); } @@ -160,4 +119,19 @@ public void booleanLit(final byte[] value) { addElem(BOOLEAN).add(value); } + + /** + * Adds a new element with the given type. + * @param type JSON type + * @return the element + */ + private FElem addElem(final byte[] type) { + final FElem e = new FElem(name); + addType(e, e.name(), type); + + if(curr != null) curr.add(e); + else curr = e; + name = null; + return e; + } } diff -Nru basex-8.1.1/basex-core/src/main/java/org/basex/io/parse/json/JsonFallback.java basex-8.2.3/basex-core/src/main/java/org/basex/io/parse/json/JsonFallback.java --- basex-8.1.1/basex-core/src/main/java/org/basex/io/parse/json/JsonFallback.java 2015-04-16 13:52:47.000000000 +0000 +++ basex-8.2.3/basex-core/src/main/java/org/basex/io/parse/json/JsonFallback.java 2015-07-14 10:54:40.000000000 +0000 @@ -12,5 +12,5 @@ * @param string input string * @return converted token */ - public abstract byte[] convert(final byte[] string); + public abstract String convert(final String string); } diff -Nru basex-8.1.1/basex-core/src/main/java/org/basex/io/parse/json/JsonMapConverter.java basex-8.2.3/basex-core/src/main/java/org/basex/io/parse/json/JsonMapConverter.java --- basex-8.1.1/basex-core/src/main/java/org/basex/io/parse/json/JsonMapConverter.java 2015-04-16 13:52:47.000000000 +0000 +++ basex-8.2.3/basex-core/src/main/java/org/basex/io/parse/json/JsonMapConverter.java 2015-07-14 10:54:40.000000000 +0000 @@ -1,8 +1,11 @@ package org.basex.io.parse.json; +import static org.basex.query.QueryError.*; + import java.util.*; import org.basex.build.json.*; +import org.basex.build.json.JsonParserOptions.JsonDuplicates; import org.basex.query.*; import org.basex.query.util.list.*; import org.basex.query.value.*; @@ -43,9 +46,13 @@ /** * Constructor. * @param opts json options + * @throws QueryIOException query I/O exception */ - JsonMapConverter(final JsonParserOptions opts) { + JsonMapConverter(final JsonParserOptions opts) throws QueryIOException { super(opts); + final JsonDuplicates dupl = jopts.get(JsonParserOptions.DUPLICATES); + if(dupl == JsonDuplicates.RETAIN) throw new QueryIOException( + BXJS_INVALID_X.get(null, JsonParserOptions.DUPLICATES.name(), dupl)); } @Override @@ -60,7 +67,7 @@ } @Override - void openPair(final byte[] key) { + void openPair(final byte[] key, final boolean add) { stack.push(Str.get(key)); } @@ -102,28 +109,6 @@ } @Override - public void openConstr(final byte[] name) { - openObject(); - openPair(name); - openArray(); - } - - @Override public void openArg() { - openItem(); - } - - @Override public void closeArg() throws QueryIOException { - closeItem(); - } - - @Override - public void closeConstr() throws QueryIOException { - closeArray(); - closePair(true); - closeObject(); - } - - @Override public void numberLit(final byte[] value) throws QueryIOException { try { stack.push(Dbl.get(value, null)); diff -Nru basex-8.1.1/basex-core/src/main/java/org/basex/io/parse/json/JsonMLConverter.java basex-8.2.3/basex-core/src/main/java/org/basex/io/parse/json/JsonMLConverter.java --- basex-8.1.1/basex-core/src/main/java/org/basex/io/parse/json/JsonMLConverter.java 2015-04-16 13:52:47.000000000 +0000 +++ basex-8.2.3/basex-core/src/main/java/org/basex/io/parse/json/JsonMLConverter.java 2015-07-14 10:54:40.000000000 +0000 @@ -67,7 +67,7 @@ } @Override - public void openPair(final byte[] key) throws QueryIOException { + public void openPair(final byte[] key, final boolean add) throws QueryIOException { attName = check(key); } @@ -150,15 +150,4 @@ public void booleanLit(final byte[] b) throws QueryIOException { error("No booleans allowed"); } - - @Override - public void openConstr(final byte[] nm) throws QueryIOException { - error("No constructor functions allowed"); - } - - @Override public void openArg() { } - - @Override public void closeArg() { } - - @Override public void closeConstr() { } } diff -Nru basex-8.1.1/basex-core/src/main/java/org/basex/io/parse/json/JsonParser.java basex-8.2.3/basex-core/src/main/java/org/basex/io/parse/json/JsonParser.java --- basex-8.1.1/basex-core/src/main/java/org/basex/io/parse/json/JsonParser.java 2015-04-16 13:52:47.000000000 +0000 +++ basex-8.2.3/basex-core/src/main/java/org/basex/io/parse/json/JsonParser.java 2015-07-14 10:54:40.000000000 +0000 @@ -4,6 +4,7 @@ import static org.basex.util.Token.*; import org.basex.build.json.*; +import org.basex.build.json.JsonOptions.*; import org.basex.build.json.JsonParserOptions.JsonDuplicates; import org.basex.query.*; import org.basex.util.*; @@ -48,7 +49,9 @@ super(in); liberal = opts.get(JsonParserOptions.LIBERAL); unescape = opts.get(JsonParserOptions.UNESCAPE); - duplicates = opts.get(JsonParserOptions.DUPLICATES); + final JsonDuplicates dupl = opts.get(JsonParserOptions.DUPLICATES); + duplicates = dupl != null ? dupl : opts.get(JsonOptions.FORMAT) == JsonFormat.BASIC ? + JsonDuplicates.RETAIN : JsonDuplicates.USE_FIRST; this.conv = conv; } @@ -73,6 +76,7 @@ * @throws QueryIOException query I/O exception */ private void parse() throws QueryIOException { + consume('\uFEFF'); skipWs(); value(); if(more()) throw error("Unexpected trailing content: %", rest()); @@ -114,7 +118,6 @@ if(consume("true")) conv.booleanLit(TRUE); else if(consume("false")) conv.booleanLit(FALSE); else if(consume("null")) conv.nullLit(); - else if(liberal && consume("new") && Character.isWhitespace(curr())) constr(); else throw error("Unexpected JSON value: '%'", rest()); skipWs(); } @@ -135,10 +138,11 @@ if(dupl && duplicates == JsonDuplicates.REJECT) throw error(BXJS_DUPLICATE_X, "Key '%' occurs more than once.", key); - conv.openPair(key); + final boolean add = !(dupl && duplicates == JsonDuplicates.USE_FIRST); + conv.openPair(key, add); consumeWs(':', true); value(); - conv.closePair(!dupl || duplicates == JsonDuplicates.USE_LAST); + conv.closePair(add); set.put(key); } while(consumeWs(',', false) && !(liberal && curr() == '}')); consumeWs('}', true); @@ -165,30 +169,6 @@ } /** - * Parses a JSON constructor function. - * @throws QueryIOException query I/O exception - */ - private void constr() throws QueryIOException { - skipWs(); - if(!input.substring(pos).matches("^[a-zA-Z0-9_-]+\\(.*")) - throw error("Wrong constructor syntax: '%'", rest()); - - final int p = input.indexOf('(', pos); - conv.openConstr(token(input.substring(pos, p))); - pos = p + 1; - skipWs(); - if(!consumeWs(')', false)) { - do { - conv.openArg(); - value(); - conv.closeArg(); - } while(consumeWs(',', false)); - consumeWs(')', true); - } - conv.closeConstr(); - } - - /** * Reads an unquoted string literal. * @return the string * @throws QueryIOException query I/O exception @@ -295,7 +275,7 @@ final int p = pos; int ch = consume(); if(ch == '"') { - if(high != 0) tb.add(INVALID); + if(high != 0) add(high, pos - 7, p); skipWs(); return tb.toArray(); } @@ -362,14 +342,14 @@ if(high != 0) { if(ch >= 0xDC00 && ch <= 0xDFFF) ch = (high - 0xD800 << 10) + ch - 0xDC00 + 0x10000; - else tb.add(INVALID); + else add(high, p, pos); high = 0; } if(ch >= 0xD800 && ch <= 0xDBFF) { high = (char) ch; } else { - add(ch, p); + add(ch, p, pos); } } throw eof(" in string literal"); @@ -378,15 +358,16 @@ /** * Adds the specified character. * @param ch character - * @param p start position of unescape sequence + * @param s start position of invalid unicode sequence + * @param e end position */ - private void add(final int ch, final int p) { + private void add(final int ch, final int s, final int e) { if(XMLToken.valid(ch)) { tb.add(ch); } else if(conv.fallback == null) { tb.add(INVALID); } else { - tb.add(conv.fallback.convert(new TokenBuilder().add(input.substring(p, pos)).finish())); + tb.add(conv.fallback.convert(input.substring(s, e))); } } diff -Nru basex-8.1.1/basex-core/src/main/java/org/basex/io/serial/AdaptiveSerializer.java basex-8.2.3/basex-core/src/main/java/org/basex/io/serial/AdaptiveSerializer.java --- basex-8.1.1/basex-core/src/main/java/org/basex/io/serial/AdaptiveSerializer.java 2015-04-16 13:52:47.000000000 +0000 +++ basex-8.2.3/basex-core/src/main/java/org/basex/io/serial/AdaptiveSerializer.java 2015-07-14 10:54:40.000000000 +0000 @@ -51,6 +51,13 @@ } @Override + public Serializer sc(final StaticContext sctx) { + xml.sc(sctx); + json.sc(sctx); + return super.sc(sctx); + } + + @Override public void serialize(final Item item) throws IOException { if(more) xml.printChars(itemsep); super.serialize(item); diff -Nru basex-8.1.1/basex-core/src/main/java/org/basex/io/serial/BuilderSerializer.java basex-8.2.3/basex-core/src/main/java/org/basex/io/serial/BuilderSerializer.java --- basex-8.1.1/basex-core/src/main/java/org/basex/io/serial/BuilderSerializer.java 2015-04-16 13:52:47.000000000 +0000 +++ basex-8.2.3/basex-core/src/main/java/org/basex/io/serial/BuilderSerializer.java 2015-07-14 10:54:40.000000000 +0000 @@ -5,7 +5,7 @@ import java.io.*; import org.basex.build.*; -import org.basex.data.*; +import org.basex.query.util.ft.*; import org.basex.util.*; /** @@ -42,14 +42,14 @@ @Override protected final void finishOpen() throws IOException { - builder.openElem(elem, atts, nsp); + builder.openElem(elem.string(), atts, nsp); atts.clear(); nsp.clear(); } @Override protected void finishEmpty() throws IOException { - builder.emptyElem(elem, atts, nsp); + builder.emptyElem(elem.string(), atts, nsp); atts.clear(); nsp.clear(); } diff -Nru basex-8.1.1/basex-core/src/main/java/org/basex/io/serial/csv/CsvDirectSerializer.java basex-8.2.3/basex-core/src/main/java/org/basex/io/serial/csv/CsvDirectSerializer.java --- basex-8.1.1/basex-core/src/main/java/org/basex/io/serial/csv/CsvDirectSerializer.java 2015-04-16 13:52:47.000000000 +0000 +++ basex-8.2.3/basex-core/src/main/java/org/basex/io/serial/csv/CsvDirectSerializer.java 2015-07-14 10:54:40.000000000 +0000 @@ -7,9 +7,10 @@ import org.basex.build.csv.*; import org.basex.build.csv.CsvOptions.CsvFormat; -import org.basex.data.*; import org.basex.io.out.*; import org.basex.io.serial.*; +import org.basex.query.util.ft.*; +import org.basex.query.value.item.*; import org.basex.util.*; import org.basex.util.hash.*; import org.basex.util.list.*; @@ -52,7 +53,7 @@ } @Override - protected void startOpen(final byte[] name) { + protected void startOpen(final QNm name) { if(level == 1) data = new TokenMap(); attv = null; } @@ -106,7 +107,7 @@ */ private void cache(final byte[] value) throws IOException { if(headers != null) { - final byte[] key = atts && attv != null ? attv : elem; + final byte[] key = atts && attv != null ? attv : elem.string(); final byte[] name = XMLToken.decode(key, lax); if(name == null) error("Invalid element name <%>", key); if(!headers.contains(name)) headers.add(name); diff -Nru basex-8.1.1/basex-core/src/main/java/org/basex/io/serial/dot/DOTData.java basex-8.2.3/basex-core/src/main/java/org/basex/io/serial/dot/DOTData.java --- basex-8.1.1/basex-core/src/main/java/org/basex/io/serial/dot/DOTData.java 2015-04-16 13:52:47.000000000 +0000 +++ basex-8.2.3/basex-core/src/main/java/org/basex/io/serial/dot/DOTData.java 2015-07-14 10:54:40.000000000 +0000 @@ -78,7 +78,7 @@ // green { "009900", GFLWOR.class }, { "339933", VarStack.class }, - { "33CC33", For.class, Let.class, List.class, Range.class, Context.class, + { "33CC33", For.class, Let.class, List.class, Range.class, ContextValue.class, QueryText.RET }, { "66CC66", Var.class, Cast.class }, // cyan diff -Nru basex-8.1.1/basex-core/src/main/java/org/basex/io/serial/dot/DOTSerializer.java basex-8.2.3/basex-core/src/main/java/org/basex/io/serial/dot/DOTSerializer.java --- basex-8.1.1/basex-core/src/main/java/org/basex/io/serial/dot/DOTSerializer.java 2015-04-16 13:52:47.000000000 +0000 +++ basex-8.2.3/basex-core/src/main/java/org/basex/io/serial/dot/DOTSerializer.java 2015-07-14 10:54:40.000000000 +0000 @@ -7,10 +7,10 @@ import java.io.*; import java.util.*; -import org.basex.data.*; import org.basex.io.out.*; import org.basex.io.serial.*; import org.basex.query.*; +import org.basex.query.util.ft.*; import org.basex.query.value.item.*; import org.basex.util.*; import org.basex.util.list.*; @@ -53,7 +53,7 @@ } @Override - protected void startOpen(final byte[] name) { + protected void startOpen(final QNm name) { tb.reset(); } @@ -65,9 +65,9 @@ @Override protected void finishOpen() throws IOException { final byte[] attr = tb.toArray(); - String color = color(elem); + String color = color(elem.string()); if(color == null) color = attr.length == 0 ? ELEM1 : ELEM2; - print(concat(elem, attr), color); + print(concat(elem.string(), attr), color); } @Override diff -Nru basex-8.1.1/basex-core/src/main/java/org/basex/io/serial/HTMLSerializer.java basex-8.2.3/basex-core/src/main/java/org/basex/io/serial/HTMLSerializer.java --- basex-8.1.1/basex-core/src/main/java/org/basex/io/serial/HTMLSerializer.java 2015-04-16 13:52:47.000000000 +0000 +++ basex-8.2.3/basex-core/src/main/java/org/basex/io/serial/HTMLSerializer.java 2015-07-14 10:54:40.000000000 +0000 @@ -7,6 +7,7 @@ import java.io.*; import org.basex.io.out.*; +import org.basex.query.value.item.*; import org.basex.util.hash.*; import org.basex.util.list.*; @@ -47,10 +48,13 @@ out.print(name); // don't append value for boolean attributes - final byte[] nm = concat(lc(elem), COLON, lc(name)); - if(BOOLEAN.contains(nm) && eq(name, value)) return; - // escape URI attributes - final byte[] val = escuri && URIS.contains(nm) ? escape(value) : value; + byte[] val = value; + if(!BOOLEAN.isEmpty() || !URIS.isEmpty()) { + final byte[] nm = concat(lc(elem.string()), ATT, lc(name)); + if(BOOLEAN.contains(nm) && eq(name, val)) return; + // escape URI attributes + if(escuri && URIS.contains(nm)) val = escape(val); + } out.print(ATT1); final int vl = val.length; @@ -61,7 +65,7 @@ } else if(ch == '"') { out.print(E_QUOT); } else if(ch == 0x9 || ch == 0xA) { - hex(ch); + printHex(ch); } else { encode(ch); } @@ -97,30 +101,31 @@ } @Override - protected void startOpen(final byte[] name) throws IOException { + protected void startOpen(final QNm name) throws IOException { doctype(null); if(sep) indent(); out.print(ELEM_O); - out.print(name); + out.print(name.string()); sep = indent; - script = SCRIPTS.contains(lc(name)); - if(content && eq(lc(elem), HEAD)) ct++; + script = SCRIPTS.contains(lc(name.local())); + if(content && eq(lc(elem.local()), HEAD)) ct++; } @Override protected void finishOpen() throws IOException { super.finishOpen(); - ct(false, true); + printCT(false, true); } @Override protected void finishEmpty() throws IOException { - if(ct(true, true)) return; + if(printCT(true, true)) return; out.print(ELEM_C); + final byte[] lc = lc(elem.local()); if(html5) { - if(EMPTIES5.contains(lc(elem))) return; + if(EMPTIES5.contains(lc)) return; } else { - if(EMPTIES.contains(lc(elem))) { + if(EMPTIES.contains(lc)) { final byte[] u = nsUri(EMPTY); if(u == null || u.length == 0) return; } @@ -132,21 +137,17 @@ @Override protected void finishClose() throws IOException { super.finishClose(); - script = script && !SCRIPTS.contains(lc(elem)); + script = script && !SCRIPTS.contains(lc(elem.local())); } @Override - boolean doctype(final byte[] type) throws IOException { - if(level != 0) return false; - if(!super.doctype(type) && html5) { - if(sep) indent(); - out.print(DOCTYPE); - if(type == null) out.print(HTML); - else out.print(type); - out.print(ELEM_C); - if(indent) newline(); + protected void doctype(final QNm type) throws IOException { + final boolean doc = docpub != null || docsys != null; + if(doc) { + printDoctype(type, docpub, docsys); + } else if(html5) { + printDoctype(type, null, null); } - return true; } // HTML Serializer: cache elements @@ -155,30 +156,30 @@ SCRIPTS.add("script"); SCRIPTS.add("style"); // boolean attributes - BOOLEAN.add("area:nohref"); - BOOLEAN.add("button:disabled"); - BOOLEAN.add("dir:compact"); - BOOLEAN.add("dl:compact"); - BOOLEAN.add("frame:noresize"); - BOOLEAN.add("hr:noshade"); - BOOLEAN.add("img:ismap"); - BOOLEAN.add("input:checked"); - BOOLEAN.add("input:disabled"); - BOOLEAN.add("input:readonly"); - BOOLEAN.add("menu:compact"); - BOOLEAN.add("object:declare"); - BOOLEAN.add("ol:compact"); - BOOLEAN.add("optgroup:disabled"); - BOOLEAN.add("option:selected"); - BOOLEAN.add("option:disabled"); - BOOLEAN.add("script:defer"); - BOOLEAN.add("select:multiple"); - BOOLEAN.add("select:disabled"); - BOOLEAN.add("td:nowrap"); - BOOLEAN.add("textarea:disabled"); - BOOLEAN.add("textarea:readonly"); - BOOLEAN.add("th:nowrap"); - BOOLEAN.add("ul:compact"); + BOOLEAN.add("area@nohref"); + BOOLEAN.add("button@disabled"); + BOOLEAN.add("dir@compact"); + BOOLEAN.add("dl@compact"); + BOOLEAN.add("frame@noresize"); + BOOLEAN.add("hr@noshade"); + BOOLEAN.add("img@ismap"); + BOOLEAN.add("input@checked"); + BOOLEAN.add("input@disabled"); + BOOLEAN.add("input@readonly"); + BOOLEAN.add("menu@compact"); + BOOLEAN.add("object@declare"); + BOOLEAN.add("ol@compact"); + BOOLEAN.add("optgroup@disabled"); + BOOLEAN.add("option@selected"); + BOOLEAN.add("option@disabled"); + BOOLEAN.add("script@defer"); + BOOLEAN.add("select@multiple"); + BOOLEAN.add("select@disabled"); + BOOLEAN.add("td@nowrap"); + BOOLEAN.add("textarea@disabled"); + BOOLEAN.add("textarea@readonly"); + BOOLEAN.add("th@nowrap"); + BOOLEAN.add("ul@compact"); // elements with an empty content model EMPTIES.add("area"); EMPTIES.add("base"); @@ -197,16 +198,13 @@ // elements with an empty content model EMPTIES5.add("area"); EMPTIES5.add("base"); - EMPTIES5.add("basefont"); EMPTIES5.add("br"); EMPTIES5.add("col"); EMPTIES5.add("command"); EMPTIES5.add("embed"); - EMPTIES5.add("frame"); EMPTIES5.add("hr"); EMPTIES5.add("img"); EMPTIES5.add("input"); - EMPTIES5.add("isindex"); EMPTIES5.add("keygen"); EMPTIES5.add("link"); EMPTIES5.add("meta"); @@ -215,42 +213,42 @@ EMPTIES5.add("track"); EMPTIES5.add("wbr"); // URI attributes - URIS.add("a:href"); - URIS.add("a:name"); - URIS.add("applet:codebase"); - URIS.add("area:href"); - URIS.add("base:href"); - URIS.add("blockquote:cite"); - URIS.add("body:background"); - URIS.add("button:datasrc"); - URIS.add("del:cite"); - URIS.add("div:datasrc"); - URIS.add("form:action"); - URIS.add("frame:longdesc"); - URIS.add("frame:src"); - URIS.add("head:profile"); - URIS.add("iframe:longdesc"); - URIS.add("iframe:src"); - URIS.add("img:longdesc"); - URIS.add("img:src"); - URIS.add("img:usemap"); - URIS.add("input:datasrc"); - URIS.add("input:src"); - URIS.add("input:usemap"); - URIS.add("ins:cite"); - URIS.add("link:href"); - URIS.add("object:archive"); - URIS.add("object:classid"); - URIS.add("object:codebase"); - URIS.add("object:data"); - URIS.add("object:datasrc"); - URIS.add("object:usemap"); - URIS.add("q:cite"); - URIS.add("script:for"); - URIS.add("script:src"); - URIS.add("select:datasrc"); - URIS.add("span:datasrc"); - URIS.add("table:datasrc"); - URIS.add("textarea:datasrc"); + URIS.add("a@href"); + URIS.add("a@name"); + URIS.add("applet@codebase"); + URIS.add("area@href"); + URIS.add("base@href"); + URIS.add("blockquote@cite"); + URIS.add("body@background"); + URIS.add("button@datasrc"); + URIS.add("del@cite"); + URIS.add("div@datasrc"); + URIS.add("form@action"); + URIS.add("frame@longdesc"); + URIS.add("frame@src"); + URIS.add("head@profile"); + URIS.add("iframe@longdesc"); + URIS.add("iframe@src"); + URIS.add("img@longdesc"); + URIS.add("img@src"); + URIS.add("img@usemap"); + URIS.add("input@datasrc"); + URIS.add("input@src"); + URIS.add("input@usemap"); + URIS.add("ins@cite"); + URIS.add("link@href"); + URIS.add("object@archive"); + URIS.add("object@classid"); + URIS.add("object@codebase"); + URIS.add("object@data"); + URIS.add("object@datasrc"); + URIS.add("object@usemap"); + URIS.add("q@cite"); + URIS.add("script@for"); + URIS.add("script@src"); + URIS.add("select@datasrc"); + URIS.add("span@datasrc"); + URIS.add("table@datasrc"); + URIS.add("textarea@datasrc"); } } diff -Nru basex-8.1.1/basex-core/src/main/java/org/basex/io/serial/json/JsonBasicSerializer.java basex-8.2.3/basex-core/src/main/java/org/basex/io/serial/json/JsonBasicSerializer.java --- basex-8.1.1/basex-core/src/main/java/org/basex/io/serial/json/JsonBasicSerializer.java 1970-01-01 00:00:00.000000000 +0000 +++ basex-8.2.3/basex-core/src/main/java/org/basex/io/serial/json/JsonBasicSerializer.java 2015-07-14 10:54:40.000000000 +0000 @@ -0,0 +1,247 @@ +package org.basex.io.serial.json; + +import static org.basex.io.parse.json.JsonConstants.*; +import static org.basex.query.QueryError.*; +import static org.basex.util.Token.*; + +import java.io.*; + +import org.basex.io.out.*; +import org.basex.io.parse.json.*; +import org.basex.io.serial.*; +import org.basex.query.*; +import org.basex.query.iter.*; +import org.basex.query.util.ft.*; +import org.basex.query.value.item.*; +import org.basex.query.value.node.*; +import org.basex.query.value.type.*; +import org.basex.util.*; +import org.basex.util.list.*; + +/** + * This class serializes items as JSON. The input must conform to the rules + * defined in the {@link JsonDirectConverter} and {@link JsonAttsConverter} class. + * + * @author BaseX Team 2005-15, BSD License + * @author Christian Gruen + */ +public final class JsonBasicSerializer extends JsonSerializer { + /** Output key. */ + private boolean printKey; + + /** + * Constructor. + * @param out print output + * @param opts serialization parameters + * @throws IOException I/O exception + */ + public JsonBasicSerializer(final PrintOutput out, final SerializerOptions opts) + throws IOException { + super(out, opts); + } + + @Override + protected void node(final ANode node) throws IOException { + if(level > 0) indent(); + + final BasicNodeIter iter = node.children(); + if(node.type == NodeType.DOC || node.type == NodeType.DEL) { + final ANode child = iter.next(); + if(child == null) throw error("Document has no child."); + if(iter.next() != null) throw error("Document has more than one child."); + node(child); + } else if(node.type == NodeType.ELM) { + final QNm name = node.qname(); + final byte[] type = name.local(); + if(!eq(name.uri(), QueryText.FN_URI)) + throw error("Element '%' has invalid namespace: '%'.", type, name.uri()); + + byte[] key = node.attribute(KEY); + if(printKey) { + if(key == null) throw error("Element '%' has no key.", type); + out.print('"'); + out.print(escape(key, node.attribute(ESCAPED_KEY))); + out.print("\":"); + } else { + if(key != null) throw error("Element '%' must have no key.", type); + } + + if(eq(type, NULL)) { + out.print(NULL); + if(iter.next() != null) throw error("Element '%' must have no children.", type); + } else if(eq(type, BOOLEAN)) { + byte[] value = value(iter, type); + if(value == null) throw error("Element '%' has no value.", type); + if(!eq(value, TRUE, FALSE)) throw error("Element '%' has invalid value: '%'.", type, value); + out.print(value); + } else if(eq(type, STRING)) { + byte[] value = value(iter, type); + out.print('"'); + if(value != null) out.print(escape(value, node.attribute(ESCAPED))); + out.print('"'); + } else if(eq(type, NUMBER)) { + byte[] value = value(iter, type); + if(value == null) throw error("Element '%' has no value.", type); + final Double d = toDouble(value); + if(d.isNaN() || d.isInfinite()) + throw error("Element '%' has invalid value: '%'.", type, value); + out.print(value); + } else if(eq(type, ARRAY)) { + out.print('['); + children(iter, false); + out.print(']'); + } else if(eq(type, MAP)) { + out.print('{'); + children(iter, true); + out.print('}'); + } else { + throw error("Invalid element: '%'", name); + } + } else { + throw error("Node must be an element."); + } + } + + @Override + protected void startOpen(final QNm name) throws IOException { + throw Util.notExpected(); + } + + @Override + protected void attribute(final byte[] name, final byte[] value, final boolean standalone) + throws IOException { + throw Util.notExpected(); + } + + @Override + protected void finishOpen() throws IOException { + throw Util.notExpected(); + } + + @Override + protected void text(final byte[] value, final FTPos ftp) throws IOException { + throw Util.notExpected(); + } + + @Override + protected void finishEmpty() throws IOException { + throw Util.notExpected(); + } + + @Override + protected void finishClose() throws IOException { + throw Util.notExpected(); + } + + @Override + protected void atomic(final Item value) throws IOException { + throw BXJS_SERIAL_X.getIO("Atomic values cannot be serialized"); + } + + /** + * Serializes child nodes. + * @param iter iterator + * @param pk print keys + * @throws IOException I/O exception + */ + private void children(final BasicNodeIter iter, final boolean pk) throws IOException { + boolean tmp = printKey; + printKey = pk; + level++; + boolean comma = false; + for(ANode child; (child = iter.next()) != null;) { + if(child.type == NodeType.ELM) { + if(comma) out.print(','); + node(child); + comma = true; + } else if(child.type == NodeType.TXT && !ws(child.string())) { + throw error("Element '%' must have no text nodes.", child.name()); + } + } + level--; + indent(); + printKey = tmp; + } + + /** + * Returns the value of a node. + * @param iter iterator + * @param type type + * @return value + * @throws QueryIOException query exception + */ + private byte[] value(final BasicNodeIter iter, final byte[] type) throws QueryIOException { + byte[] value = null; + for(ANode child; (child = iter.next()) != null;) { + if(child.type == NodeType.TXT) { + if(value != null) throw error("Element '%' has more than one child.", type); + value = child.string(); + } else if(child.type == NodeType.ELM) { + throw error("Element '%' must have no elements as child.", type); + } + } + return value; + } + + /** + * Returns a possibly escaped value. + * @param value value to escape + * @param flag escape flag + * @return escaped value + * @throws QueryIOException I/O exception + */ + private byte[] escape(final byte[] value, final byte[] flag) throws QueryIOException { + if(flag != null && !eq(flag, FALSE, TRUE)) + throw error("Value of escape attribute is invalid: '%'.", flag); + + final boolean check = flag != null && eq(flag, TRUE); + if(check) { + if(contains(value, '\\')) { + final TokenParser tp = new TokenParser(value); + while(tp.more()) { + int c = tp.next(); + if(c == '\\') { + if(!tp.more()) throw JSON_ESCAPE_X.getIO(value); + c = tp.next(); + if(indexOf(ESCAPES, c) == -1) throw JSON_ESCAPE_X.getIO(value); + if(c == 'u') { + for(int i = 0; i < 4; i++) { + if(!tp.more()) throw JSON_ESCAPE_X.getIO(value); + c = tp.next(); + if(c < '0' || c > '9' && c < 'A' || c > 'F' && c < 'a' || c > 'f') + throw JSON_ESCAPE_X.getIO(value); + } + } + } + } + } + } + + final ByteList bl = new ByteList(); + for(final byte c : value) { + if(c < 32 || c >= 128 && c <= 160) { + bl.add('\\'); + if(c == '\b') bl.add('b'); + else if(c == '\f') bl.add('f'); + else if(c == '\n') bl.add('n'); + else if(c == '\r') bl.add('r'); + else if(c == '\t') bl.add('t'); + else bl.add('u').add('0').add('0').add(HEX[c >> 4]).add(HEX[c & 0xF]); + } else { + if(c == '"' || !check && c == '\\') bl.add('\\'); + bl.add(c); + } + } + return bl.finish(); + } + + /** + * Raises an error with the specified message. + * @param msg error message + * @param ext error details + * @return I/O exception + */ + private static QueryIOException error(final String msg, final Object... ext) { + return JSON_INVALID_X.getIO(Util.inf(msg, ext)); + } +} diff -Nru basex-8.1.1/basex-core/src/main/java/org/basex/io/serial/json/JsonMLSerializer.java basex-8.2.3/basex-core/src/main/java/org/basex/io/serial/json/JsonMLSerializer.java --- basex-8.1.1/basex-core/src/main/java/org/basex/io/serial/json/JsonMLSerializer.java 2015-04-16 13:52:47.000000000 +0000 +++ basex-8.2.3/basex-core/src/main/java/org/basex/io/serial/json/JsonMLSerializer.java 2015-07-14 10:54:40.000000000 +0000 @@ -1,13 +1,12 @@ package org.basex.io.serial.json; import static org.basex.query.QueryError.*; -import static org.basex.util.Token.*; import java.io.*; -import org.basex.data.*; import org.basex.io.out.*; import org.basex.io.serial.*; +import org.basex.query.util.ft.*; import org.basex.query.value.item.*; /** @@ -36,13 +35,13 @@ } @Override - protected void startOpen(final byte[] name) throws IOException { + protected void startOpen(final QNm name) throws IOException { if(level != 0) { out.print(','); indent(); } out.print("[\""); - for(final byte ch : local(name)) encode(ch); + for(final byte ch : name.local()) encode(ch); out.print('"'); att = false; } diff -Nru basex-8.1.1/basex-core/src/main/java/org/basex/io/serial/json/JsonNodeSerializer.java basex-8.2.3/basex-core/src/main/java/org/basex/io/serial/json/JsonNodeSerializer.java --- basex-8.1.1/basex-core/src/main/java/org/basex/io/serial/json/JsonNodeSerializer.java 2015-04-16 13:52:47.000000000 +0000 +++ basex-8.2.3/basex-core/src/main/java/org/basex/io/serial/json/JsonNodeSerializer.java 2015-07-14 10:54:40.000000000 +0000 @@ -8,12 +8,13 @@ import org.basex.build.json.*; import org.basex.build.json.JsonOptions.JsonFormat; -import org.basex.data.*; import org.basex.io.out.*; import org.basex.io.parse.json.*; import org.basex.io.serial.*; import org.basex.query.*; +import org.basex.query.util.ft.*; import org.basex.query.value.*; +import org.basex.query.value.item.*; import org.basex.query.value.node.*; import org.basex.query.value.type.*; import org.basex.util.*; @@ -100,10 +101,10 @@ } @Override - protected void startOpen(final byte[] name) throws IOException { + protected void startOpen(final QNm name) throws IOException { types.set(level, null); comma.set(level + 1, false); - key = atts ? null : name; + key = atts ? null : name.string(); } @Override @@ -127,7 +128,7 @@ types.set(level, value); } else if(atts && eq(name, NAME)) { key = value; - if(!eq(elem, PAIR)) throw error("<%> found,A container/list for atomic updates. Updates must be added from the lowest to + * the highest PRE value (regarding the location of the update). Updates are finally + * applied by this container from the highest to the lowest PRE value (reverse document + * order) to support efficient structural bulk updates etc.
+ * + *If a collection of updates is carried out via the AUC there are several + * benefits:
+ * + *To avoid ambiguity it is not allowed to add:
+ *Updates are added in a streaming fashion where the most recently added update is + * remembered. This avoids additional traversals of the AUC during consistency checks and + * further optimizations.
+ * + * @author BaseX Team 2005-15, BSD License + * @author Lukas Kircher + */ +public final class AtomicUpdateCache { + /** List of structural updates (nodes are inserted to / deleted from the table. */ + private final List