* XML<>JSON conversion problems [https://github.com/clicon/clixon/issues/66]
* CDATA sections stripped from XML when converted to JSON
This commit is contained in:
parent
906b93cae0
commit
19f26e6838
4 changed files with 149 additions and 51 deletions
|
|
@ -134,6 +134,8 @@
|
||||||
* <!DOCTYPE (ie DTD) is not supported.
|
* <!DOCTYPE (ie DTD) is not supported.
|
||||||
|
|
||||||
### Corrected Bugs
|
### Corrected Bugs
|
||||||
|
* XML<>JSON conversion problems [https://github.com/clicon/clixon/issues/66]
|
||||||
|
* CDATA sections stripped from XML when converted to JSON
|
||||||
* Restconf returns error when RPC generates "ok" reply [https://github.com/clicon/clixon/issues/69]
|
* Restconf returns error when RPC generates "ok" reply [https://github.com/clicon/clixon/issues/69]
|
||||||
* xsd regular expression support for character classes [https://github.com/clicon/clixon/issues/68]
|
* xsd regular expression support for character classes [https://github.com/clicon/clixon/issues/68]
|
||||||
* added support for \c, \d, \w, \W, \s, \S.
|
* added support for \c, \d, \w, \W, \s, \S.
|
||||||
|
|
|
||||||
|
|
@ -216,42 +216,58 @@ array_eval(cxobj *xprev,
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Escape a json string
|
/*! Escape a json string as well as decode xml cdata
|
||||||
|
* And a
|
||||||
*/
|
*/
|
||||||
static char *
|
static int
|
||||||
json_str_escape(char *str)
|
json_str_escape_cdata(cbuf *cb,
|
||||||
|
char *str)
|
||||||
{
|
{
|
||||||
int i, j;
|
int retval = -1;
|
||||||
char *snew;
|
char *snew = NULL;
|
||||||
|
int i;
|
||||||
|
int esc = 0; /* cdata escape */
|
||||||
|
|
||||||
j = 0;
|
|
||||||
for (i=0;i<strlen(str);i++)
|
for (i=0;i<strlen(str);i++)
|
||||||
switch (str[i]){
|
switch (str[i]){
|
||||||
case '\n':
|
case '\n':
|
||||||
case '\"':
|
cprintf(cb, "\\n");
|
||||||
case '\\':
|
|
||||||
j++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if ((snew = malloc(strlen(str)+1+j))==NULL){
|
|
||||||
clicon_err(OE_XML, errno, "malloc");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
j = 0;
|
|
||||||
for (i=0;i<strlen(str);i++)
|
|
||||||
switch (str[i]){
|
|
||||||
case '\n':
|
|
||||||
snew[j++]='\\';
|
|
||||||
snew[j++]='n';
|
|
||||||
break;
|
break;
|
||||||
case '\"':
|
case '\"':
|
||||||
|
cprintf(cb, "\\\"");
|
||||||
|
break;
|
||||||
case '\\':
|
case '\\':
|
||||||
snew[j++]='\\';
|
cprintf(cb, "\\\\");
|
||||||
|
break;
|
||||||
|
case '<':
|
||||||
|
if (!esc &&
|
||||||
|
strncmp(&str[i], "<![CDATA[", strlen("<![CDATA[")) == 0){
|
||||||
|
esc=1;
|
||||||
|
i += strlen("<![CDATA[")-1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cprintf(cb, "%c", str[i]);
|
||||||
|
break;
|
||||||
|
case ']':
|
||||||
|
if (esc &&
|
||||||
|
strncmp(&str[i], "]]>", strlen("]]>")) == 0){
|
||||||
|
esc=0;
|
||||||
|
i += strlen("]]>")-1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cprintf(cb, "%c", str[i]);
|
||||||
|
break;
|
||||||
default: /* fall thru */
|
default: /* fall thru */
|
||||||
snew[j++]=str[i];
|
cprintf(cb, "%c", str[i]);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
snew[j++]='\0';
|
if ((snew = strdup(cbuf_get(cb))) ==NULL){
|
||||||
return snew;
|
clicon_err(OE_XML, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Do the actual work of translating XML to JSON
|
/*! Do the actual work of translating XML to JSON
|
||||||
|
|
@ -309,10 +325,10 @@ xml2json1_cbuf(cbuf *cb,
|
||||||
yang_stmt *ymod; /* yang module */
|
yang_stmt *ymod; /* yang module */
|
||||||
yang_spec *yspec = NULL; /* yang spec */
|
yang_spec *yspec = NULL; /* yang spec */
|
||||||
int bodystr0=1;
|
int bodystr0=1;
|
||||||
char *str;
|
|
||||||
char *prefix=NULL; /* prefix / local namespace name */
|
char *prefix=NULL; /* prefix / local namespace name */
|
||||||
char *namespace=NULL; /* namespace uri */
|
char *namespace=NULL; /* namespace uri */
|
||||||
char *modname=NULL; /* Module name */
|
char *modname=NULL; /* Module name */
|
||||||
|
int commas;
|
||||||
|
|
||||||
/* If x is labelled with a default namespace, it should be translated
|
/* If x is labelled with a default namespace, it should be translated
|
||||||
* to a module name.
|
* to a module name.
|
||||||
|
|
@ -337,10 +353,11 @@ xml2json1_cbuf(cbuf *cb,
|
||||||
switch(arraytype){
|
switch(arraytype){
|
||||||
case BODY_ARRAY:{
|
case BODY_ARRAY:{
|
||||||
if (bodystr){
|
if (bodystr){
|
||||||
if ((str = json_str_escape(xml_value(x))) == NULL)
|
/* XXX String if right type */
|
||||||
|
cprintf(cb, "\"");
|
||||||
|
if (json_str_escape_cdata(cb, xml_value(x)) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
cprintf(cb, "\"%s\"", str);
|
cprintf(cb, "\"");
|
||||||
free(str);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
cprintf(cb, "%s", xml_value(x));
|
cprintf(cb, "%s", xml_value(x));
|
||||||
|
|
@ -434,8 +451,7 @@ xml2json1_cbuf(cbuf *cb,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int na = xml_child_nr_notype(x, CX_ATTR);
|
commas = xml_child_nr_notype(x, CX_ATTR) - 1;
|
||||||
int commas = na - 1;
|
|
||||||
for (i=0; i<xml_child_nr(x); i++){
|
for (i=0; i<xml_child_nr(x); i++){
|
||||||
xc = xml_child_i(x, i);
|
xc = xml_child_i(x, i);
|
||||||
if (xml_type(xc) == CX_ATTR)
|
if (xml_type(xc) == CX_ATTR)
|
||||||
|
|
|
||||||
59
test/lib.sh
59
test/lib.sh
|
|
@ -1,6 +1,14 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Define test functions.
|
# Define test functions.
|
||||||
# Create working dir as variable "dir"
|
# Create working dir as variable "dir"
|
||||||
|
# The functions are somewhat wildgrown, a little too many:
|
||||||
|
# - expectfn
|
||||||
|
# - expecteq
|
||||||
|
# - expecteof
|
||||||
|
# - expecteofx
|
||||||
|
# - expecteof_file
|
||||||
|
# - expectwait
|
||||||
|
# - expectmatch
|
||||||
|
|
||||||
#set -e
|
#set -e
|
||||||
|
|
||||||
|
|
@ -160,11 +168,53 @@ expecteq(){
|
||||||
# - expected command return value (0 if OK)
|
# - expected command return value (0 if OK)
|
||||||
# - stdin input
|
# - stdin input
|
||||||
# - expected stdout outcome
|
# - expected stdout outcome
|
||||||
|
# Use this if you want regex eg ^foo$
|
||||||
expecteof(){
|
expecteof(){
|
||||||
cmd=$1
|
cmd=$1
|
||||||
retval=$2
|
retval=$2
|
||||||
input=$3
|
input=$3
|
||||||
expect=$4
|
expect=$4
|
||||||
|
# Do while read stuff
|
||||||
|
ret=$($cmd<<EOF
|
||||||
|
$input
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
r=$?
|
||||||
|
if [ $r != $retval ]; then
|
||||||
|
echo -e "\e[31m\nError ($r != $retval) in Test$testnr [$testname]:"
|
||||||
|
echo -e "\e[0m:"
|
||||||
|
exit -1
|
||||||
|
fi
|
||||||
|
# If error dont match output strings (why not?)
|
||||||
|
# if [ $r != 0 ]; then
|
||||||
|
# return
|
||||||
|
# fi
|
||||||
|
# Match if both are empty string
|
||||||
|
if [ -z "$ret" -a -z "$expect" ]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
# -E for regexp (eg ^$). -Z for nul character, -x for implicit ^$ -q for quiet
|
||||||
|
# -o only matching
|
||||||
|
# Two variants: -EZo and -Fxq
|
||||||
|
# match=`echo "$ret" | grep -FZo "$expect"`
|
||||||
|
r=$(echo "$ret" | grep -GZo "$expect")
|
||||||
|
match=$?
|
||||||
|
# echo "r:\"$r\""
|
||||||
|
# echo "ret:\"$ret\""
|
||||||
|
# echo "expect:\"$expect\""
|
||||||
|
# echo "match:\"$match\""
|
||||||
|
if [ $match -ne 0 ]; then
|
||||||
|
err "$expect" "$ret"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Like expecteof but with grep -Fxq instead of -EZq. Ie implicit ^$
|
||||||
|
# Use this for fixed all line, ie must match exact.
|
||||||
|
expecteofx(){
|
||||||
|
cmd=$1
|
||||||
|
retval=$2
|
||||||
|
input=$3
|
||||||
|
expect=$4
|
||||||
|
|
||||||
# Do while read stuff
|
# Do while read stuff
|
||||||
ret=$($cmd<<EOF
|
ret=$($cmd<<EOF
|
||||||
|
|
@ -185,11 +235,16 @@ EOF
|
||||||
if [ -z "$ret" -a -z "$expect" ]; then
|
if [ -z "$ret" -a -z "$expect" ]; then
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
match=`echo "$ret" | grep -GZo "$expect"`
|
# -E for regexp (eg ^$). -Z for nul character, -x for implicit ^$ -q for quiet
|
||||||
|
# -o only matching
|
||||||
|
# Two variants: -EZo and -Fxq
|
||||||
|
# match=`echo "$ret" | grep -FZo "$expect"`
|
||||||
|
r=$(echo "$ret" | grep -Fxq "$expect")
|
||||||
|
match=$?
|
||||||
# echo "ret:\"$ret\""
|
# echo "ret:\"$ret\""
|
||||||
# echo "expect:\"$expect\""
|
# echo "expect:\"$expect\""
|
||||||
# echo "match:\"$match\""
|
# echo "match:\"$match\""
|
||||||
if [ -z "$match" ]; then
|
if [ $match -ne 0 ]; then
|
||||||
err "$expect" "$ret"
|
err "$expect" "$ret"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,22 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Test: XML parser tests
|
# Test: XML parser tests and JSON translation
|
||||||
# @see https://www.w3.org/TR/2008/REC-xml-20081126
|
# @see https://www.w3.org/TR/2008/REC-xml-20081126
|
||||||
# https://www.w3.org/TR/2009/REC-xml-names-20091208
|
# https://www.w3.org/TR/2009/REC-xml-names-20091208
|
||||||
#PROG="valgrind --leak-check=full --show-leak-kinds=all ../util/clixon_util_xml"
|
#PROG="valgrind --leak-check=full --show-leak-kinds=all ../util/clixon_util_xml"
|
||||||
|
|
||||||
|
|
||||||
# include err() and new() functions and creates $dir
|
# include err() and new() functions and creates $dir
|
||||||
. ./lib.sh
|
. ./lib.sh
|
||||||
|
|
||||||
|
|
||||||
PROG="../util/clixon_util_xml -D $DBG"
|
PROG="../util/clixon_util_xml -D $DBG"
|
||||||
|
|
||||||
new "xml parse"
|
new "xml parse"
|
||||||
expecteof "$PROG" 0 "<a><b/></a>" "^<a><b/></a>$"
|
expecteof "$PROG" 0 "<a><b/></a>" "^<a><b/></a>$"
|
||||||
|
|
||||||
new "xml parse to json"
|
new "xml parse to json"
|
||||||
expecteof "$PROG -j" 0 "<a><b/></a>" '^{"a": {"b": null}}$'
|
expecteof "$PROG -j" 0 "<a><b/></a>" '{"a": {"b": null}}'
|
||||||
|
|
||||||
new "xml parse strange names"
|
new "xml parse strange names"
|
||||||
expecteof "$PROG" 0 "<_-><b0.><c-.-._/></b0.></_->" "^<_-><b0.><c-.-._/></b0.></_->$"
|
expecteof "$PROG" 0 "<_-><b0.><c-.-._/></b0.></_->" "<_-><b0.><c-.-._/></b0.></_->"
|
||||||
|
|
||||||
new "xml parse name errors"
|
new "xml parse name errors"
|
||||||
expecteof "$PROG" 255 "<-a/>" ""
|
expecteof "$PROG" 255 "<-a/>" ""
|
||||||
|
|
@ -37,11 +35,16 @@ if [ "$ret" != "<x>a${LF}b${LF}c${LF}d</x>" ]; then
|
||||||
err '<x>a$LFb$LFc</x>' "$ret"
|
err '<x>a$LFb$LFc</x>' "$ret"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
new "xml simple CDATA"
|
||||||
|
expecteofx "$PROG" 0 '<a><![CDATA[a text]]></a>' '<a><![CDATA[a text]]></a>'
|
||||||
|
|
||||||
|
new "xml simple CDATA to json"
|
||||||
|
expecteofx "$PROG -j" 0 '<a><![CDATA[a text]]></a>' '{"a": "a text"}'
|
||||||
|
|
||||||
|
new "xml complex CDATA"
|
||||||
XML=$(cat <<EOF
|
XML=$(cat <<EOF
|
||||||
<a><description>An example of escaped CENDs</description>
|
<a><description>An example of escaped CENDs</description>
|
||||||
<sometext>
|
<sometext><![CDATA[ They're saying "x < y" & that "z > y" so I guess that means that z > x ]]></sometext>
|
||||||
<![CDATA[ They're saying "x < y" & that "z > y" so I guess that means that z > x ]]>
|
|
||||||
</sometext>
|
|
||||||
<!-- This text contains a CEND ]]> -->
|
<!-- This text contains a CEND ]]> -->
|
||||||
<!-- In this first case we put the ]] at the end of the first CDATA block
|
<!-- In this first case we put the ]] at the end of the first CDATA block
|
||||||
and the > in the second CDATA block -->
|
and the > in the second CDATA block -->
|
||||||
|
|
@ -53,33 +56,55 @@ XML=$(cat <<EOF
|
||||||
EOF
|
EOF
|
||||||
)
|
)
|
||||||
|
|
||||||
new "xml CDATA"
|
|
||||||
expecteof "$PROG" 0 "$XML" "^<a><description>An example of escaped CENDs</description><sometext>
|
expecteof "$PROG" 0 "$XML" "^<a><description>An example of escaped CENDs</description><sometext>
|
||||||
<![CDATA[ They're saying \"x < y\" & that \"z > y\" so I guess that means that z > x ]]>
|
<![CDATA[ They're saying \"x < y\" & that \"z > y\" so I guess that means that z > x ]]>
|
||||||
</sometext><data><![CDATA[This text contains a CEND ]]]]><![CDATA[>]]></data><alternative><![CDATA[This text contains a CEND ]]]><![CDATA[]>]]></alternative></a>$"
|
</sometext><data><![CDATA[This text contains a CEND ]]]]><![CDATA[>]]></data><alternative><![CDATA[This text contains a CEND ]]]><![CDATA[]>]]></alternative></a>$"
|
||||||
|
|
||||||
|
JSON=$(cat <<EOF
|
||||||
|
{"a": {"description": "An example of escaped CENDs","sometext": " They're saying \"x < y\" & that \"z > y\" so I guess that means that z > x ","data": "This text contains a CEND ]]>","alternative": "This text contains a CEND ]]>"}}
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
new "xml complex CDATA to json"
|
||||||
|
expecteofx "$PROG -j" 0 "$XML" "$JSON"
|
||||||
|
|
||||||
XML=$(cat <<EOF
|
XML=$(cat <<EOF
|
||||||
<message>Less than: < , greater than: > ampersand: & </message>
|
<message>Less than: < , greater than: > ampersand: & </message>
|
||||||
EOF
|
EOF
|
||||||
)
|
)
|
||||||
new "xml encode <>&"
|
new "xml encode <>&"
|
||||||
expecteof "$PROG" 0 "$XML" "^$XML$"
|
expecteof "$PROG" 0 "$XML" "$XML"
|
||||||
|
|
||||||
|
new "xml encode <>& to json"
|
||||||
|
expecteof "$PROG -j" 0 "$XML" '{"message": "Less than: < , greater than: > ampersand: & "}'
|
||||||
|
|
||||||
XML=$(cat <<EOF
|
XML=$(cat <<EOF
|
||||||
<message>To allow attribute values to contain both single and double quotes, the apostrophe or single-quote character ' may be represented as ' and the double-quote character as "</message>
|
<message>single-quote character ' represented as ' and double-quote character as "</message>
|
||||||
EOF
|
EOF
|
||||||
)
|
)
|
||||||
new "xml optional encode single and double quote"
|
new "xml single and double quote"
|
||||||
expecteof "$PROG" 0 "$XML" "^<message>To allow attribute values to contain both single and double quotes, the apostrophe or single-quote character ' may be represented as ' and the double-quote character as \"</message>$"
|
expecteof "$PROG" 0 "$XML" "<message>single-quote character ' represented as ' and double-quote character as \"</message>"
|
||||||
|
|
||||||
|
JSON=$(cat <<EOF
|
||||||
|
{"message": "single-quote character ' represented as ' and double-quote character as \""}
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
new "xml single and double quotes to json"
|
||||||
|
expecteofx "$PROG -j" 0 "$XML" "$JSON"
|
||||||
|
|
||||||
|
new "xml backspace"
|
||||||
|
expecteofx "$PROG" 0 "<a>a\b</a>" "<a>a\b</a>"
|
||||||
|
|
||||||
|
new "xml backspace to json"
|
||||||
|
expecteofx "$PROG -j" 0 "<a>a\b</a>" '{"a": "a\\b"}'
|
||||||
|
|
||||||
new "Double quotes for attributes"
|
new "Double quotes for attributes"
|
||||||
expecteof "$PROG" 0 '<x a="t"/>' '^<x a="t"/>$'
|
expecteof "$PROG" 0 '<x a="t"/>' '<x a="t"/>'
|
||||||
|
|
||||||
new "Single quotes for attributes (returns double quotes but at least parses right)"
|
new "Single quotes for attributes (returns double quotes but at least parses right)"
|
||||||
expecteof "$PROG" 0 "<x a='t'/>" '^<x a="t"/>$'
|
expecteof "$PROG" 0 "<x a='t'/>" '<x a="t"/>'
|
||||||
|
|
||||||
new "Mixed quotes"
|
new "Mixed quotes"
|
||||||
expecteof "$PROG" 0 "<x a='t' b=\"q\"/>" '^<x a="t" b="q"/>$'
|
expecteof "$PROG" 0 "<x a='t' b=\"q\"/>" '<x a="t" b="q"/>'
|
||||||
|
|
||||||
new "XMLdecl version"
|
new "XMLdecl version"
|
||||||
expecteof "$PROG" 0 '<?xml version="1.0"?><a/>' '<a/>'
|
expecteof "$PROG" 0 '<?xml version="1.0"?><a/>' '<a/>'
|
||||||
|
|
@ -94,7 +119,7 @@ new "XMLdecl no version"
|
||||||
expecteof "$PROG" 255 '<?xml ?><a/>' ''
|
expecteof "$PROG" 255 '<?xml ?><a/>' ''
|
||||||
|
|
||||||
new "XMLdecl misspelled version"
|
new "XMLdecl misspelled version"
|
||||||
expecteof "$PROG -l o" 255 '<?xml verion="1.0"?><a/>' 'yntax error: at or before: v'
|
expecteof "$PROG -l o" 255 '<?xml verion="1.0"?><a/>' ''
|
||||||
|
|
||||||
new "XMLdecl version + encoding"
|
new "XMLdecl version + encoding"
|
||||||
expecteof "$PROG" 0 '<?xml version="1.0" encoding="UTF-16"?><a/>' '<a/>'
|
expecteof "$PROG" 0 '<?xml version="1.0" encoding="UTF-16"?><a/>' '<a/>'
|
||||||
|
|
@ -119,7 +144,7 @@ expecteof "$PROG" 0 '<?foo something ?><a/><?bar more stuff ?><!-- a comment-->'
|
||||||
#expecteof "$PROG" 255 '<a/><b/>' ''
|
#expecteof "$PROG" 255 '<a/><b/>' ''
|
||||||
|
|
||||||
new "namespace: DefaultAttName"
|
new "namespace: DefaultAttName"
|
||||||
expecteof "$PROG" 0 '<x xmlns="n1">hello</x>' '^<x xmlns="n1">hello</x>$'
|
expecteof "$PROG" 0 '<x xmlns="n1">hello</x>' '<x xmlns="n1">hello</x>'
|
||||||
|
|
||||||
new "namespace: PrefixedAttName"
|
new "namespace: PrefixedAttName"
|
||||||
expecteof "$PROG" 0 '<x xmlns:n2="urn:example:des"><n2:y>hello</n2:y></x>' '^<x xmlns:n2="urn:example:des"><n2:y>hello</n2:y></x>$'
|
expecteof "$PROG" 0 '<x xmlns:n2="urn:example:des"><n2:y>hello</n2:y></x>' '^<x xmlns:n2="urn:example:des"><n2:y>hello</n2:y></x>$'
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue