Line data Source code
1 : /*
2 : * Package : xml2json
3 : * Author : S. Hamblett <steve.hamblett@linux.com>
4 : * Date : 12/09/2013
5 : * Copyright : S.Hamblett@OSCF
6 : *
7 : * Badgerfish conversion class.
8 : *
9 : * The Badgerfish convention is a fairly comprehensive JSON representation of XML in
10 : * the sense that it accommodates element attributes and namespaces. Unfortunately,
11 : * this also adds a bit of overhead to the JSON syntax.
12 : *
13 : * Transforms as follows :-
14 : *
15 : * Element names become object properties
16 : * Text content of elements goes in the $ property of an object.
17 : * Nested elements become nested properties
18 : * Multiple elements at the same level become named array elements.
19 : * Attributes go in properties whose names begin with @.
20 : * Multiple attributes at the same level become array elements.
21 : * Active namespaces for an element go in the element's @xmlns property.
22 : * The default namespace URI goes in @xmlns.$.
23 : * Other namespaces go in other properties of @xmlns.
24 : * Elements with namespace prefixes become object properties, too.
25 : * The @xmlns property goes only in the object relative to the element where namespace was declared.
26 : *
27 : */
28 :
29 : part of xml2json;
30 :
31 : class _Xml2JsonBadgerfish {
32 : /// Badgerfish transformer function.
33 : ///
34 : /// This is ported from an original javascript implementation here :-
35 : /// http://ruchirawageesha.blogspot.co.uk/2011/01/xml-to-badgerfish-converter-in.html
36 :
37 : final String _marker = '"\$"';
38 : final String _xmlnsPrefix = '"@xmlns"';
39 : final String _cdata = '"__cdata"';
40 :
41 : Map _transform(XmlDocument node) {
42 1 : final json = {};
43 :
44 : void _process(var node, var obj, var ns) {
45 1 : if (node is XmlText) {
46 : /* Text node processing */
47 : final String sanitisedNodeData =
48 2 : _Xml2JsonUtils.escapeTextForJson(node.text);
49 2 : final String nodeData = '"' + sanitisedNodeData + '"';
50 4 : if (obj["$_marker"] is List) {
51 0 : obj["$_marker"].add(nodeData);
52 4 : } else if (obj["$_marker"] is Map) {
53 0 : obj["$_marker"] = [obj["$_marker"], nodeData];
54 : } else {
55 3 : obj["$_marker"] = nodeData;
56 : }
57 1 : } else if (node is XmlElement) {
58 : /* Element node processing */
59 1 : final p = {};
60 2 : final nodeName = "\"${node.name}\"";
61 4 : for (var i = 0; i < node.attributes.length; i++) {
62 2 : final attr = node.attributes[i];
63 2 : final name = attr.name.qualified;
64 1 : final value = attr.value;
65 1 : if (name == "xmlns") {
66 5 : ns["$_marker"] = '"' + value + '"';
67 2 : } else if (name.indexOf("xmlns:") == 0) {
68 3 : String namePrefix = name.substring(name.indexOf(":") + 1);
69 2 : namePrefix = '"' + namePrefix + '"';
70 3 : ns[namePrefix] = '"' + value + '"';
71 : } else {
72 1 : final String indexName = '"@$name"';
73 3 : p[indexName] = '"' + value + '"';
74 : }
75 : }
76 :
77 1 : if (ns.isNotEmpty) {
78 3 : for (var prefix in ns.keys) {
79 2 : if (!p.containsKey(_xmlnsPrefix)) {
80 1 : final List pList = new List<Map>();
81 2 : p[_xmlnsPrefix] = pList;
82 : }
83 1 : final Map nameMap = new Map<String, String>();
84 2 : nameMap[prefix] = ns[prefix];
85 3 : p[_xmlnsPrefix].add(nameMap);
86 : }
87 : }
88 :
89 2 : if (obj[nodeName] is List) {
90 2 : obj[nodeName].add(p);
91 2 : } else if (obj[nodeName] is Map) {
92 3 : obj[nodeName] = [obj[nodeName], p];
93 : } else {
94 1 : obj[nodeName] = p;
95 : }
96 4 : for (var j = 0; j < node.children.length; j++) {
97 4 : _process(node.children[j], p, {});
98 : }
99 1 : } else if (node is XmlCDATA) {
100 : /* CDATA node processing */
101 2 : final sanitisedNodeData = _Xml2JsonUtils.escapeTextForJson(node.text);
102 2 : final String nodeData = '"' + sanitisedNodeData + '"';
103 3 : obj["$_cdata"] = nodeData;
104 1 : } else if (node is XmlDocument) {
105 : /* Document node processing */
106 4 : for (var k = 0; k < node.children.length; k++) {
107 4 : _process(node.children[k], obj, {});
108 : }
109 : }
110 : }
111 2 : _process(node, json, {});
112 : return json;
113 : }
114 :
115 : /// Transformer function
116 : String transform(XmlDocument xmlNode) {
117 : Map json = null;
118 : try {
119 1 : json = _transform(xmlNode);
120 : } catch (e) {
121 0 : throw new Xml2JsonException(
122 0 : "Badgerfish internal transform error => ${e.toString()}");
123 : }
124 1 : return json.toString();
125 : }
126 : }
|