-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathxml-util.xqy
145 lines (132 loc) · 3.6 KB
/
xml-util.xqy
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
135
136
137
138
139
140
141
142
143
144
145
xquery version '1.0-ml';
module namespace xutil = "http://twotheleft.com/xml-util";
declare option xdmp:mapping "false";
(:~
: This functions takes a sequence of strings, or a map and returns a map made
: by alternating the values as key value pairs
:
: @author Josh Meekhof
: @version 1
: @param $ns a sequence of xs:strings or a map:map
: @return map:map
:)
declare function xutil:parse-alternating-sequence( $ns as item()+) as map:map
{
if ( $ns[1] instance of xs:string ) then
let $count := fn:count($ns) idiv 2 (:how many alternating groups do I have:)
let $entry :=
(1 to $count) !
map:entry( fn:subsequence($ns, (.) * 2 -1, 1), fn:subsequence($ns, (.) * 2, 1 ) )
return map:new($entry)
else if ( $ns instance of map:map ) then
$ns
else
fn:error()
};
(:~
: returns a namespace suitable for insertion in an element contructor
: @author Josh Meekhof
: @version 1
: @param $ns-map a sequence of xs:string or map:map
: @return namespace
:)
declare function xutil:namespace-axis(
$ns-map as item()+) as item()*
{
let $ns := xutil:parse-alternating-sequence($ns-map)
let $e := "<e " ||
string-join(
for $prefix in map:keys($ns)
return
if ( $prefix = "" ) then
'xmlns="' || map:get($ns, $prefix) || '"'
else
'xmlns:' || $prefix || '="' || map:get($ns, $prefix) || '"'
," ")
|| '/>'
return xdmp:unquote($e)/*/namespace::*
};
(:~
: returns a node with the namespace prefixes normalized throughout
: @author Josh Meekhof
: @version 1
: @param $node the document or node to be operated upon
: @param $ns alternating sequence of prefix, namespace or a map:map
: @return The nodes with normalized namespaces
:)
declare function xutil:clean-ns-deep(
$node as node(),
$ns as item()+) as node()*
{
let $node :=
if ($node instance of document-node() ) then
$node/*
else
$node
let $ns := xutil:parse-alternating-sequence($ns)
return
element { fn:node-name($node) }
{
xutil:namespace-axis($ns),
xutil:ns-clean-deep-recurse($node/node(),$ns)
}
};
declare function xutil:ns-clean-deep-recurse(
$nodes as node()*,
$ns-map as map:map) as node()*
{
let $reverse-map := -$ns-map
for $node in $nodes
return
if ($node instance of element() ) then
let $ns := fn:namespace-uri($node)
return
if ( map:contains($reverse-map, $ns) ) then
(
let $prefix := map:get($reverse-map, $ns)
return
element {
fn:QName (
$ns,
concat(
$prefix,
if ( $prefix = '') then
''
else
':',
fn:local-name($node) ) ) } { $node/@*,
xutil:ns-clean-deep-recurse($node/node(), $ns-map) }
)
else
(
$node,
xutil:ns-clean-deep-recurse($node/node(), $ns-map)
)
else
$node
};
(:~
: Recursively walks through a node and removes the empty elements
: @param $node the node you want to have the empty elements removed
: @return the element with all the empty nodes removed
:)
declare function xutil:remove-empty-elements($node as node()) as element()? {
let $element :=
if ($node instance of document-node() ) then
$node/*
else
$node
return
if ( $element/* or $element/text() ) then
element { fn:node-name($element) } {
$element/@*, $element/node() !
(
if ( . instance of element() ) then
xutil:remove-empty-elements(.)
else
.
)
}
else
()
};