-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathjson.jq
134 lines (125 loc) · 4.22 KB
/
json.jq
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
module {
name: "json",
description: "JSON utilities",
namespace: "fadado.github.io",
author: {
name: "Joan Josep Ordinas Rosa",
email: "[email protected]"
}
};
include "fadado.github.io/prelude";
include "fadado.github.io/types";
import "fadado.github.io/string/ascii" as ascii;
import "fadado.github.io/string/regexp" as re;
# Is a JQ syntactic correct identifier?
def isid: #:: string => boolean
length > 0
and ascii::isword
and (.[0:1] | false==ascii::isdigit)
;
def isid($s): #:: string => boolean
$s | isid
;
########################################################################
# JSON to XML rendering
# kind of XML token: Name (1), Nmtoken (2), other (0)
def _xtok: #:: string => number
"[_:A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\\x{00010000}-\\x{000EFFFF}]"
as $NameStartChar |
("(:?"+$NameStartChar+"|"+"[-.·0-9\u0300-\u036F\u203F-\u2040])")
as $NameChar |
("^"+$NameChar+"+"+"$")
as $Nmtoken |
# ("^"+$NameStartChar+$NameChar+"*"+"$") as $Name |
if re::test($Nmtoken)
then if re::test("^"+$NameStartChar) then 1 else 2 end
else 0
end
;
# Is an XML Name?
def xname: #:: string => boolean
_xtok == 1
;
def xname($s): #:: (string) => boolean
$s | _xtok == 1
;
# Is an XML Nmtoken?
def xtoken: #:: string => boolean
_xtok == 2
;
def xtoken($s): #:: (string) => boolean
$s | _xtok == 2
;
# JSON to XML
def xmldoc($root; $element; $tab; $doctype): #:: JSON|(string;string;string;string^null) => XML
# construct a valid XML name
def name($x):
"_:A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\\x{00010000}-\\x{000EFFFF}"
as $NameStartChar |
($NameStartChar+"-.·0-9\u0300-\u036F\u203F-\u2040")
as $NameChar |
$x
| re::gsub("[^"+$NameChar+"]"; "_")
| if false==re::test("^["+$NameStartChar+"]")
then "_"+.[1:] end
;
# recurse document
def toxml($name; $margin):
if isnull
then "\($margin)<\($name) json:type='null'/>"
elif isboolean or isnumber or isstring
then "\($margin)<\($name) json:type='\(type)'>\(.)</\($name)>"
elif isarray
then
if length==0 then
"\($margin)<\($name) json:type='array'/>"
else
"\($margin)<\($name) json:type='array'>",
(.[] | toxml($element; $margin+$tab)),
"\($margin)</\($name)>"
end
else # isobject
if length==0 then
"\($margin)<\($name) json:type='object'/>"
else
"\($margin)<\($name) json:type='object'>",
(keys_unsorted[] as $k | .[$k] | toxml(name($k); $margin+$tab)),
"\($margin)</\($name)>"
end
end
;
# expect valid named for root element and array elements
assert(xname($root); "expected valid XML Name (\($root))") |
assert(xname($element); "expected valid XML Name (\($element))")|
# namespace for json: prefix
"xmlns:json='https://github.com/fadado/JBOL'" as $xmlns |
# render document
"<?xml version='1.0' encoding='utf-8' standalone='yes'?>",
$doctype//empty,
if isnull
then "<json:\($root) \($xmlns) json:type='null'/>"
elif isboolean or isnumber or isstring
then "<json:\($root) \($xmlns) json:type='\(type)'>\(.)</json:\($root)>"
elif isarray
then
if length==0 then
"<json:\($root) \($xmlns) json:type='array'/>"
else
"<json:\($root) \($xmlns) json:type='array'>",
(.[] | toxml($element; $tab)),
"</json:\($root)>"
end
else # isobject
if length==0 then
"<json:\($root) \($xmlns) json:type='object'/>"
else
"<json:\($root) \($xmlns) json:type='object'>",
(keys_unsorted[] as $k | .[$k] | toxml(name($k); $tab)),
"</json:\($root)>"
end
end
;
def xmldoc: #:: JSON => XML
xmldoc("document"; "element"; " "; null)
;
# vim:ai:sw=4:ts=4:et:syntax=jq