Skip to content

Commit

Permalink
JSON-related functions
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastian Baechle committed Mar 29, 2012
1 parent 79a9cc7 commit 7574df2
Show file tree
Hide file tree
Showing 4 changed files with 373 additions and 0 deletions.
47 changes: 47 additions & 0 deletions src/main/java/org/brackit/xquery/function/io/IOFun.java
@@ -0,0 +1,47 @@
/*
* [New BSD License]
* Copyright (c) 2011-2012, Brackit Project Team <info@brackit.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Brackit Project Team nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.brackit.xquery.function.io;

import org.brackit.xquery.atomic.QNm;

/**
* @author Sebastian Baechle
*
*/
public class IOFun {
public static final String IO_NSURI = "http://brackit.org/ns/io";

public static final String IO_PREFIX = "io";

public static final QNm IO_LOADFILE_INT_ERROR = new QNm(IO_NSURI,
IO_PREFIX, "BIIO0001");

public static final QNm IO_WRITEFILE_INT_ERROR = new QNm(IO_NSURI,
IO_PREFIX, "BIIO002");

}
43 changes: 43 additions & 0 deletions src/main/java/org/brackit/xquery/function/json/JSONFun.java
@@ -0,0 +1,43 @@
/*
* [New BSD License]
* Copyright (c) 2011-2012, Brackit Project Team <info@brackit.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Brackit Project Team nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.brackit.xquery.function.json;

import org.brackit.xquery.atomic.QNm;

/**
* @author Sebastian Baechle
*
*/
public class JSONFun {
public static final String JSON_NSURI = "http://brackit.org/ns/json";

public static final String JSON_PREFIX = "json";

public static final QNm ERR_PARSING_ERROR = new QNm(JSON_NSURI,
JSON_PREFIX, "BIJS0001");
}
68 changes: 68 additions & 0 deletions src/main/java/org/brackit/xquery/function/json/JSONParse.java
@@ -0,0 +1,68 @@
/*
* [New BSD License]
* Copyright (c) 2011-2012, Brackit Project Team <info@brackit.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Brackit Project Team nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.brackit.xquery.function.json;

import org.brackit.xquery.QueryContext;
import org.brackit.xquery.QueryException;
import org.brackit.xquery.atomic.QNm;
import org.brackit.xquery.atomic.Str;
import org.brackit.xquery.function.AbstractFunction;
import org.brackit.xquery.module.StaticContext;
import org.brackit.xquery.xdm.Sequence;
import org.brackit.xquery.xdm.Signature;
import org.brackit.xquery.xdm.type.AtomicType;
import org.brackit.xquery.xdm.type.Cardinality;
import org.brackit.xquery.xdm.type.DocumentType;
import org.brackit.xquery.xdm.type.SequenceType;

/**
*
* @author Sebastian Baechle
*
*/
public class JSONParse extends AbstractFunction {

public static final QNm PARSE = new QNm(JSONFun.JSON_NSURI, JSONFun.JSON_PREFIX,
"parse");

public JSONParse() {
super(PARSE, new Signature(new SequenceType(DocumentType.DOC,
Cardinality.One), new SequenceType(AtomicType.STR,
Cardinality.ZeroOrOne)), true);
}

@Override
public Sequence execute(StaticContext sctx, QueryContext ctx,
Sequence[] args) throws QueryException {
Str s = (Str) args[0];
if (s == null) {
return null;
}
return new JSONParser(s.stringValue()).parse();
}
}
215 changes: 215 additions & 0 deletions src/main/java/org/brackit/xquery/function/json/JSONParser.java
@@ -0,0 +1,215 @@
/*
* [New BSD License]
* Copyright (c) 2011-2012, Brackit Project Team <info@brackit.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Brackit Project Team nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.brackit.xquery.function.json;

import java.util.ArrayList;

import org.brackit.xquery.QueryException;
import org.brackit.xquery.array.DArray;
import org.brackit.xquery.atomic.Bool;
import org.brackit.xquery.atomic.Dbl;
import org.brackit.xquery.atomic.Dec;
import org.brackit.xquery.atomic.Int32;
import org.brackit.xquery.atomic.Numeric;
import org.brackit.xquery.atomic.QNm;
import org.brackit.xquery.atomic.Str;
import org.brackit.xquery.compiler.parser.Tokenizer;
import org.brackit.xquery.record.ArrayRecord;
import org.brackit.xquery.util.serialize.StringSerializer;
import org.brackit.xquery.xdm.Item;

/**
* <p>
* Simple recursive descent parser for JSON documents.
* </p>
* <p>
* Note this parser is not 100% conform to the JSON RFC because we simply reuse
* parts from the general (XQuery) {@link Tokenizer}. When we have time, we
* should make it JSON conform. ;-)
* </p>
*
* @author Sebastian Baechle
*
*/
public class JSONParser extends Tokenizer {

public JSONParser(String query) {
super(query);
}

public Item parse() throws QueryException {
try {
Item i = object();
i = (i != null) ? i : array();
if (i == null) {
throw new QueryException(JSONFun.ERR_PARSING_ERROR,
"No JSON data found");
}
consumeEOF();
return i;
} catch (IllegalCharRefException e) {
throw new QueryException(e, JSONFun.ERR_PARSING_ERROR, e.getMessage());
} catch (Exception e) {
throw new QueryException(e, JSONFun.ERR_PARSING_ERROR, e.getMessage());
}
}

protected void consumeSkipS(String token) throws TokenizerException {
Token la = laSkipS(token);
if (la == null) {
throw new TokenizerException("Expected '%s': '%s'", token,
paraphrase());
}
consume(la);
}

private Item value(boolean required) throws TokenizerException,
QueryException {
Item i = string();
i = (i != null) ? i : number();
i = (i != null) ? i : object();
i = (i != null) ? i : array();
i = (i != null) ? i : symbol(required);
return i;
}

private Item symbol(boolean required) throws TokenizerException {
if (attemptSkipS("true")) {
return Bool.TRUE;
} else if (attemptSkipS("false")) {
return Bool.FALSE;
} else if (attemptSkipS("null")) {
return null;
} else if (required) {
throw new TokenizerException("JSON value expected: %s",
paraphrase());
}
return null;
}

private Item array() throws TokenizerException, QueryException {
if (!attemptSkipS("[")) {
return null;
}
if (attemptSkipS("]")) {
return new ArrayRecord(new QNm[0], new Item[0]);
}
ArrayList<Item> values = new ArrayList<Item>();
do {
values.add(value(true));
} while (attemptSkipS(","));
consumeSkipS("]");

return new DArray(values.toArray(new Item[values.size()]));
}

private Item object() throws TokenizerException, QueryException {
if (!attemptSkipS("{")) {
return null;
}
if (attemptSkipS("}")) {
return new ArrayRecord(new QNm[0], new Item[0]);
}
int len = 0;
ArrayList<QNm> fields = new ArrayList<QNm>();
ArrayList<Item> values = new ArrayList<Item>();
do {
Str name = string();
if (name == null) {

}
consumeSkipS(":");
Item value = value(true);
fields.add(new QNm(null, null, name.stringValue()));
values.add(value);
len++;
} while (attemptSkipS(","));
consumeSkipS("}");

return new ArrayRecord(fields.toArray(new QNm[len]),
values.toArray(new Item[len]));
}

private Numeric number() throws QueryException, TokenizerException {
Token la = laS();
if (la != null) {
Token la2 = laInteger(la, true);
if (la2 != null) {
consume(la);
consume(la2);
return Int32.parse(la2.string());
} else if ((la2 = laDecimal(la, true)) != null) {
consume(la);
consume(la2);
return new Dec(la2.string());
} else if ((la2 = laDouble(la, true)) != null) {
consume(la);
consume(la2);
return new Dbl(la2.string());
}
} else {
la = laInteger(true);
if (la != null) {
consume(la);
return Int32.parse(la.string());
} else if ((la = laDecimal(true)) != null) {
consume(la);
return new Dec(la.string());
} else if ((la = laDouble(true)) != null) {
consume(la);
return new Dbl(la.string());
}
}
return null;
}

private Str string() throws TokenizerException {
Token la = laS();
if (la != null) {
Token la2 = laString(la, true);
if (la2 != null) {
consume(la);
consume(la2);
return new Str(la2.string());
}
} else {
la = laString(true);
if (la != null) {
consume(la);
return new Str(la.string());
}
}
return null;
}

public static void main(String[] args) throws Exception {
String s = "{\"bindings\": [ {\"ircEvent\": \"PRIVMSG\", \"method\": \"newURI\", \"regex\": \"^http://.*\"}, {\"ircEvent\": \"PRIVMSG\", \"method\": \"deleteURI\", \"regex\": \"^delete.*\"}, {\"ircEvent\": \"PRIVMSG\", \"method\": \"randomURI\", \"regex\": \"^random.*\"} ]}";
Item item = new JSONParser(s).parse();
new StringSerializer(System.out).serialize(item);
}
}

0 comments on commit 7574df2

Please sign in to comment.