zorba-coders team mailing list archive
-
zorba-coders team
-
Mailing list archive
-
Message #13947
[Merge] lp:~zorba-coders/zorba/bug-1047547 into lp:zorba
Matthias Brantner has proposed merging lp:~zorba-coders/zorba/bug-1047547 into lp:zorba.
Requested reviews:
Ghislain Fourny (gislenius)
Related bugs:
Bug #1047547 in Zorba: "jn:parse-json needs options and be able to handle sequences"
https://bugs.launchpad.net/zorba/+bug/1047547
For more details, see:
https://code.launchpad.net/~zorba-coders/zorba/bug-1047547/+merge/123396
- jn:parse-json to allow multiple top-level items
- added jn:parse-json#2 taking an options parameter
--
https://code.launchpad.net/~zorba-coders/zorba/bug-1047547/+merge/123396
Your team Zorba Coders is subscribed to branch lp:zorba.
=== modified file 'include/zorba/pregenerated/diagnostic_list.h'
--- include/zorba/pregenerated/diagnostic_list.h 2012-08-30 13:45:43 +0000
+++ include/zorba/pregenerated/diagnostic_list.h 2012-09-08 01:52:17 +0000
@@ -848,6 +848,8 @@
extern ZORBA_DLL_PUBLIC JSONiqErrorCode JNTY0003;
extern ZORBA_DLL_PUBLIC JSONiqErrorCode JSDY0040;
+
+extern ZORBA_DLL_PUBLIC JSONiqErrorCode JSDY0041;
#endif
} // namespace jerr
=== modified file 'modules/org/jsoniq/www/functions.xq'
--- modules/org/jsoniq/www/functions.xq 2012-09-05 12:22:23 +0000
+++ modules/org/jsoniq/www/functions.xq 2012-09-08 01:52:17 +0000
@@ -39,19 +39,49 @@
declare namespace err = "http://www.w3.org/2005/xqt-errors";
+declare namespace jerr = "http://www.jsoniq.org/errors";
+
declare namespace ver = "http://www.zorba-xquery.com/options/versioning";
declare option ver:module-version "1.0";
(:~
- : This function has the same semantics as fn:parse-xml(), except that
- : it parses the string as JSON (not XML), and returns an Object or
- : Array rather than an XML document.
- :
- : @param $j A string containing a valid JSON text.
- : @return a JSON Object or Array item.
- :)
-declare function jn:parse-json($j as xs:string) as json-item()? external;
+ : This function parses a given string as JSON and returns a sequence
+ : of Objects or Arrays.
+ :
+ : Please note that this function allows to parse sequences of whitespace
+ : separated objects and arrays.
+ :
+ : @param $j A string containing a valid JSON text.
+ :
+ : @return A sequence of JSON Object or Array item.
+ :
+ : @error jerr:JSDY0040 if the given string is not valid JSON.
+ :)
+declare function jn:parse-json($j as xs:string) as json-item()* external;
+
+(:~
+ : This function parses a given string as JSON and returns a sequence
+ : of Objects or Arrays.
+ :
+ : @param $j A string containing a valid JSON text.
+ : @param $o A JSON object defining options to configure the parser.
+ : Allowed options are
+ : <ul>
+ : <li>jsoniq-multiple-top-level-items: allow parsing of sequences of JSON Objects and Arrays (boolean; default: true)</li>
+ : </ul>
+ :
+ : @error jerr:JSDY0040 if the given string is not valid JSON or
+ : if jsoniq-multiple-top-level-items is false and there is additionalx
+ : content after the first JSON Object or Array.
+ : @error jerr:JSDY0041 if the value for the option
+ : jsoniq-multiple-top-level-items is not of type xs:boolean.
+ :
+ : @return a sequence of JSON Object or Array item.
+ :)
+declare function jn:parse-json(
+ $j as xs:string,
+ $o as object()) as json-item()* external;
(:~
=== modified file 'modules/org/jsoniq/www/pregenerated/errors.xq'
--- modules/org/jsoniq/www/pregenerated/errors.xq 2012-08-30 13:45:43 +0000
+++ modules/org/jsoniq/www/pregenerated/errors.xq 2012-09-08 01:52:17 +0000
@@ -141,4 +141,9 @@
(:~
:parser errors raised by the JSONIQLoader
:)
-declare variable $jerr:JSDY0040 as xs:QName := fn:QName($jerr:NS, "jerr:JSDY0040");
\ No newline at end of file
+declare variable $jerr:JSDY0040 as xs:QName := fn:QName($jerr:NS, "jerr:JSDY0040");
+
+(:~
+ :parser error for invalid option type
+:)
+declare variable $jerr:JSDY0041 as xs:QName := fn:QName($jerr:NS, "jerr:JSDY0041");
\ No newline at end of file
=== modified file 'src/diagnostics/diagnostic_en.xml'
--- src/diagnostics/diagnostic_en.xml 2012-08-31 19:53:50 +0000
+++ src/diagnostics/diagnostic_en.xml 2012-09-08 01:52:17 +0000
@@ -2700,6 +2700,11 @@
<value>$1</value>
</diagnostic>
+ <diagnostic code="JSDY0041" if="defined(ZORBA_WITH_JSON)">
+ <comment>parser error for invalid option type</comment>
+ <value>$1: invalid option type for option $2 (expected $3)</value>
+ </diagnostic>
+
</namespace>
<!--////////// Zorba Warnings ////////////////////////////////////////////-->
@@ -3947,6 +3952,10 @@
<value>unterminated JSON string${ at 2}</value>
</entry>
+ <entry key="JSON_UNEXPECTED_EXTRA_CONTENT">
+ <value>unexpected extra content at the end of the document (consider using the jsoniq-multiple-top-level-items option)</value>
+ </entry>
+
</subvalues>
</diagnostic-list>
=== modified file 'src/diagnostics/pregenerated/diagnostic_list.cpp'
--- src/diagnostics/pregenerated/diagnostic_list.cpp 2012-08-30 13:45:43 +0000
+++ src/diagnostics/pregenerated/diagnostic_list.cpp 2012-09-08 01:52:17 +0000
@@ -1247,6 +1247,9 @@
JSONiqErrorCode JSDY0040( "JSDY0040" );
+
+
+JSONiqErrorCode JSDY0041( "JSDY0041" );
#endif
=== modified file 'src/diagnostics/pregenerated/dict_en.cpp'
--- src/diagnostics/pregenerated/dict_en.cpp 2012-08-31 19:53:50 +0000
+++ src/diagnostics/pregenerated/dict_en.cpp 2012-09-08 01:52:17 +0000
@@ -154,6 +154,9 @@
#if defined(ZORBA_WITH_JSON)
{ "JSDY0040", "$1" },
#endif
+#if defined(ZORBA_WITH_JSON)
+ { "JSDY0041", "$1: invalid option type for option $2 (expected $3)" },
+#endif
{ "SENR0001", "\"$1\": can not serialize $2" },
{ "SEPM0004", "doctype-system parameter, or standalone parameter with a value other than \"omit\", specified" },
{ "SEPM0009", "omit-xml-declaration parameter is \"yes\" and $1" },
@@ -607,6 +610,7 @@
{ "~JSON_ILLEGAL_ESCAPE", "'\\$2': illegal JSON character escape${ at 3}" },
{ "~JSON_ILLEGAL_LITERAL", "illegal JSON literal${ at 2}" },
{ "~JSON_ILLEGAL_NUMBER", "illegal JSON number${ at 2}" },
+ { "~JSON_UNEXPECTED_EXTRA_CONTENT", "unexpected extra content at the end of the document (consider using the jsoniq-multiple-top-level-items option)" },
{ "~JSON_UNEXPECTED_TOKEN", "\"$2\": unexpected JSON token${ at 3}" },
{ "~JSON_UNTERMINATED_STRING", "unterminated JSON string${ at 2}" },
{ "~JSONiq dynamic error", "JSONIQ dynamic error" },
=== modified file 'src/functions/pregenerated/func_jsoniq_functions.cpp'
--- src/functions/pregenerated/func_jsoniq_functions.cpp 2012-08-30 13:45:43 +0000
+++ src/functions/pregenerated/func_jsoniq_functions.cpp 2012-09-08 01:52:17 +0000
@@ -202,8 +202,8 @@
{
DECL_WITH_KIND(sctx, fn_jsoniq_parse_json,
(createQName("http://www.jsoniq.org/functions","","parse-json"),
- GENV_TYPESYSTEM.STRING_TYPE_ONE,
- GENV_TYPESYSTEM.JSON_ITEM_TYPE_QUESTION),
+ GENV_TYPESYSTEM.STRING_TYPE_QUESTION,
+ GENV_TYPESYSTEM.JSON_ITEM_TYPE_STAR),
FunctionConsts::FN_JSONIQ_PARSE_JSON_1);
}
@@ -216,6 +216,23 @@
{
+ DECL_WITH_KIND(sctx, fn_jsoniq_parse_json,
+ (createQName("http://www.jsoniq.org/functions","","parse-json"),
+ GENV_TYPESYSTEM.STRING_TYPE_QUESTION,
+ GENV_TYPESYSTEM.JSON_OBJECT_TYPE_ONE,
+ GENV_TYPESYSTEM.JSON_ITEM_TYPE_STAR),
+ FunctionConsts::FN_JSONIQ_PARSE_JSON_2);
+
+ }
+
+
+#endif
+
+
+#ifdef ZORBA_WITH_JSON
+
+
+ {
DECL_WITH_KIND(sctx, fn_jsoniq_keys,
(createQName("http://www.jsoniq.org/functions","","keys"),
GENV_TYPESYSTEM.JSON_OBJECT_TYPE_ONE,
=== modified file 'src/functions/pregenerated/function_enum.h'
--- src/functions/pregenerated/function_enum.h 2012-08-30 13:45:43 +0000
+++ src/functions/pregenerated/function_enum.h 2012-09-08 01:52:17 +0000
@@ -226,6 +226,7 @@
FN_ZORBA_JSON_PARSE_INTERNAL_2,
FN_ZORBA_JSON_SERIALIZE_INTERNAL_2,
FN_JSONIQ_PARSE_JSON_1,
+ FN_JSONIQ_PARSE_JSON_2,
FN_JSONIQ_KEYS_1,
FN_JSONIQ_VALUE_2,
FN_JSONIQ_PROJECT_2,
=== modified file 'src/runtime/json/jsoniq_functions_impl.cpp'
--- src/runtime/json/jsoniq_functions_impl.cpp 2012-08-30 13:45:43 +0000
+++ src/runtime/json/jsoniq_functions_impl.cpp 2012-09-08 01:52:17 +0000
@@ -53,52 +53,125 @@
/*******************************************************************************
********************************************************************************/
+void
+JSONParseIteratorState::init(PlanState& aState)
+{
+ PlanIteratorState::init(aState);
+ theAllowMultiple = true; // default
+ theInputStream = 0;
+ theGotOne = false;
+}
+
+void
+JSONParseIteratorState::reset(PlanState& aState)
+{
+ PlanIteratorState::reset(aState);
+ if (theInput == NULL && theInputStream)
+ {
+ delete theInputStream;
+ }
+}
+
+JSONParseIteratorState::~JSONParseIteratorState()
+{
+ if (theInput == NULL && theInputStream)
+ {
+ delete theInputStream;
+ }
+}
+
bool
JSONParseIterator::nextImpl(
store::Item_t& result,
PlanState& planState) const
{
store::Item_t lInput;
+ store::Item_t lOptions;
- PlanIteratorState* state;
- DEFAULT_STACK_INIT(PlanIteratorState, state, planState);
+ JSONParseIteratorState* state;
+ DEFAULT_STACK_INIT(JSONParseIteratorState, state, planState);
consumeNext(lInput, theChildren[0].getp(), planState);
+ if (theChildren.size() == 2)
+ {
+ consumeNext(lOptions, theChildren[1].getp(), planState);
+
+ store::Item_t lOptionName, lOptionValue;
+
+ zstring s("jsoniq-multiple-top-level-items");
+ GENV_ITEMFACTORY->createString(lOptionName, s);
+ lOptionValue = lOptions->getObjectValue(lOptionName);
+ if (lOptionValue != NULL)
+ {
+ store::SchemaTypeCode lType = lOptionValue->getTypeCode();
+ if (!TypeOps::is_subtype(lType, store::XS_BOOLEAN))
+ {
+ const TypeManager* tm = theSctx->get_typemanager();
+ xqtref_t lType = tm->create_value_type(lOptionValue, loc);
+ RAISE_ERROR(jerr::JSDY0041, loc,
+ ERROR_PARAMS(lType->toSchemaString(), s, "xs:boolean"));
+ }
+ state->theAllowMultiple = lOptionValue->getBooleanValue();
+ }
+ }
if (lInput->isStreamable())
{
- result = GENV_STORE.parseJSON(lInput->getStream(), 0);
+ state->theInput = lInput;
+ state->theInputStream = &lInput->getStream();
}
else
{
- std::stringstream lStr;
- lStr << lInput->getStringValue();
-
- if (theRelativeLocation == QueryLoc::null)
- {
- try
- {
- result = GENV_STORE.parseJSON(lStr, 0);
- }
- catch (zorba::ZorbaException& e)
- {
- set_source(e, theChildren[0]->getLocation());
- throw;
- }
- }
- else
- {
- // pass the query location of the StringLiteral to the JSON
- // parser such that it can give better error locations.
- // Also, parseJSON already raises an XQueryException with the
- // location. Hence, no need to catch and rethrow the exception here
- zorba::internal::diagnostic::location lLoc;
- lLoc = ERROR_LOC(theRelativeLocation);
- result = GENV_STORE.parseJSON(lStr, &lLoc);
- }
- }
-
- STACK_PUSH(true, state);
+ state->theInputStream = new std::stringstream(
+ lInput->getStringValue().c_str());
+ }
+
+ while (true)
+ {
+ if (state->theInput != NULL)
+ {
+ result = GENV_STORE.parseJSON(*state->theInputStream, 0);
+ }
+ else
+ {
+ if (theRelativeLocation == QueryLoc::null)
+ {
+ try
+ {
+ result = GENV_STORE.parseJSON(*state->theInputStream, 0);
+ }
+ catch (zorba::ZorbaException& e)
+ {
+ set_source(e, theChildren[0]->getLocation());
+ throw;
+ }
+ }
+ else
+ {
+ // pass the query location of the StringLiteral to the JSON
+ // parser such that it can give better error locations.
+ // Also, parseJSON already raises an XQueryException with the
+ // location. Hence, no need to catch and rethrow the exception here
+ zorba::internal::diagnostic::location lLoc;
+ lLoc = ERROR_LOC(theRelativeLocation);
+ result = GENV_STORE.parseJSON(*state->theInputStream, &lLoc);
+ }
+ }
+ if (result != NULL)
+ {
+ if (!state->theAllowMultiple && state->theGotOne)
+ {
+ RAISE_ERROR(jerr::JSDY0040, loc,
+ ERROR_PARAMS(ZED(JSON_UNEXPECTED_EXTRA_CONTENT)));
+ }
+ state->theGotOne = true;
+ STACK_PUSH(true, state);
+ }
+ else
+ {
+ break;
+ }
+ }
STACK_END(state);
}
=== modified file 'src/runtime/json/pregenerated/jsoniq_functions.cpp'
--- src/runtime/json/pregenerated/jsoniq_functions.cpp 2012-08-30 13:45:43 +0000
+++ src/runtime/json/pregenerated/jsoniq_functions.cpp 2012-09-08 01:52:17 +0000
@@ -39,7 +39,7 @@
void JSONParseIterator::serialize(::zorba::serialization::Archiver& ar)
{
serialize_baseclass(ar,
- (NaryBaseIterator<JSONParseIterator, PlanIteratorState>*)this);
+ (NaryBaseIterator<JSONParseIterator, JSONParseIteratorState>*)this);
ar & theRelativeLocation;
}
@@ -60,6 +60,8 @@
JSONParseIterator::~JSONParseIterator() {}
+JSONParseIteratorState::JSONParseIteratorState() {}
+
// </JSONParseIterator>
#endif
=== modified file 'src/runtime/json/pregenerated/jsoniq_functions.h'
--- src/runtime/json/pregenerated/jsoniq_functions.h 2012-08-30 13:45:43 +0000
+++ src/runtime/json/pregenerated/jsoniq_functions.h 2012-09-08 01:52:17 +0000
@@ -38,7 +38,23 @@
*
* Author:
*/
-class JSONParseIterator : public NaryBaseIterator<JSONParseIterator, PlanIteratorState>
+class JSONParseIteratorState : public PlanIteratorState
+{
+public:
+ bool theAllowMultiple; //
+ store::Item_t theInput; //
+ std::istream* theInputStream; //
+ bool theGotOne; //
+
+ JSONParseIteratorState();
+
+ ~JSONParseIteratorState();
+
+ void init(PlanState&);
+ void reset(PlanState&);
+};
+
+class JSONParseIterator : public NaryBaseIterator<JSONParseIterator, JSONParseIteratorState>
{
protected:
QueryLoc theRelativeLocation; //
@@ -46,7 +62,7 @@
SERIALIZABLE_CLASS(JSONParseIterator);
SERIALIZABLE_CLASS_CONSTRUCTOR2T(JSONParseIterator,
- NaryBaseIterator<JSONParseIterator, PlanIteratorState>);
+ NaryBaseIterator<JSONParseIterator, JSONParseIteratorState>);
void serialize( ::zorba::serialization::Archiver& ar);
@@ -56,7 +72,7 @@
std::vector<PlanIter_t>& children,
QueryLoc aRelativeLocation)
:
- NaryBaseIterator<JSONParseIterator, PlanIteratorState>(sctx, loc, children),
+ NaryBaseIterator<JSONParseIterator, JSONParseIteratorState>(sctx, loc, children),
theRelativeLocation(aRelativeLocation)
{}
=== modified file 'src/runtime/spec/json/jsoniq_functions.xml'
--- src/runtime/spec/json/jsoniq_functions.xml 2012-08-30 13:45:43 +0000
+++ src/runtime/spec/json/jsoniq_functions.xml 2012-09-08 01:52:17 +0000
@@ -18,8 +18,14 @@
<zorba:function isDeterministic="true" generateCodegen="false">
<zorba:signature localname="parse-json" prefix="fn-jsoniq">
- <zorba:param>xs:string</zorba:param>
- <zorba:output>json-item()?</zorba:output>
+ <zorba:param>xs:string?</zorba:param>
+ <zorba:output>json-item()*</zorba:output>
+ </zorba:signature>
+
+ <zorba:signature localname="parse-json" prefix="fn-jsoniq">
+ <zorba:param>xs:string?</zorba:param>
+ <zorba:param>object()</zorba:param>
+ <zorba:output>json-item()*</zorba:output>
</zorba:signature>
<zorba:methods>
@@ -29,6 +35,13 @@
</zorba:function>
+ <zorba:state generateInit="false" generateReset="false" generateDestructor="false">
+ <zorba:member type="bool" name="theAllowMultiple" brief=""/>
+ <zorba:member type="store::Item_t" name="theInput" brief=""/>
+ <zorba:member type="std::istream*" name="theInputStream" brief=""/>
+ <zorba:member type="bool" name="theGotOne"/>
+ </zorba:state>
+
<zorba:constructor>
<zorba:parameter type="QueryLoc" name="aRelativeLocation" />
</zorba:constructor>
Follow ups
-
[Merge] lp:~zorba-coders/zorba/bug-1047547 into lp:zorba
From: noreply, 2012-09-11
-
[Merge] lp:~zorba-coders/zorba/bug-1047547 into lp:zorba
From: Zorba Build Bot, 2012-09-11
-
[Merge] lp:~zorba-coders/zorba/bug-1047547 into lp:zorba
From: Zorba Build Bot, 2012-09-11
-
[Merge] lp:~zorba-coders/zorba/bug-1047547 into lp:zorba
From: Matthias Brantner, 2012-09-11
-
[Merge] lp:~zorba-coders/zorba/bug-1047547 into lp:zorba
From: Zorba Build Bot, 2012-09-11
-
Re: [Merge] lp:~zorba-coders/zorba/bug-1047547 into lp:zorba
From: Zorba Build Bot, 2012-09-11
-
[Merge] lp:~zorba-coders/zorba/bug-1047547 into lp:zorba
From: Ghislain Fourny, 2012-09-11
-
Re: [Merge] lp:~zorba-coders/zorba/bug-1047547 into lp:zorba
From: Ghislain Fourny, 2012-09-11
-
[Merge] lp:~zorba-coders/zorba/bug-1047547 into lp:zorba
From: Zorba Build Bot, 2012-09-10
-
Re: [Merge] lp:~zorba-coders/zorba/bug-1047547 into lp:zorba
From: Zorba Build Bot, 2012-09-10
-
[Merge] lp:~zorba-coders/zorba/bug-1047547 into lp:zorba
From: Zorba Build Bot, 2012-09-10
-
[Merge] lp:~zorba-coders/zorba/bug-1047547 into lp:zorba
From: Zorba Build Bot, 2012-09-10
-
Re: [Merge] lp:~zorba-coders/zorba/bug-1047547 into lp:zorba
From: Matthias Brantner, 2012-09-10
-
[Merge] lp:~zorba-coders/zorba/bug-1047547 into lp:zorba
From: Matthias Brantner, 2012-09-10