|
1 function updateDocumentSourceMaps(source) { |
|
2 const nsIDOMNode = Components.interfaces.nsIDOMNode; |
|
3 |
|
4 const nsISAXXMLReader = Components.interfaces.nsISAXXMLReader; |
|
5 const saxReader = Components.classes["@mozilla.org/saxparser/xmlreader;1"] |
|
6 .createInstance(nsISAXXMLReader); |
|
7 try { |
|
8 saxReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true); |
|
9 saxReader.setFeature("http://xml.org/sax/features/namespace", true); |
|
10 } |
|
11 catch (e) { |
|
12 // do nothing, we'll accept it as it is. |
|
13 } |
|
14 var parseErrorLog = []; |
|
15 |
|
16 /* XXX ajvincent Because throwing an exception doesn't stop parsing, we need |
|
17 * to record errors and handle them after the parsing is finished. |
|
18 */ |
|
19 function do_parse_check(aCondition, aMsg) { |
|
20 if (!aCondition) |
|
21 parseErrorLog[parseErrorLog.length] = aMsg; |
|
22 } |
|
23 |
|
24 var contentHandler = { |
|
25 startDocument: function startDocument() { |
|
26 }, |
|
27 |
|
28 endDocument: function endDocument() { |
|
29 }, |
|
30 |
|
31 handleAttributes: function handleAttributes(aAttributes) { |
|
32 for (var i = 0; i < aAttributes.length; i++) { |
|
33 var attrNamespaceURI = aAttributes.getURI(i); |
|
34 var attrLocalName = aAttributes.getLocalName(i); |
|
35 var attrNodeName = aAttributes.getQName(i); |
|
36 var value = aAttributes.getValue(i); |
|
37 do_parse_check(attrLocalName, "Missing attribute local name"); |
|
38 do_parse_check(attrNodeName, "Missing attribute node name"); |
|
39 } |
|
40 }, |
|
41 |
|
42 startElement: function startElement(aNamespaceURI, aLocalName, aNodeName, aAttributes) { |
|
43 do_parse_check(aLocalName, "Missing element local name (startElement)"); |
|
44 do_parse_check(aNodeName, "Missing element node name (startElement)"); |
|
45 do_parse_check(aAttributes, "Missing element attributes"); |
|
46 this.handleAttributes(aAttributes); |
|
47 }, |
|
48 |
|
49 endElement: function endElement(aNamespaceURI, aLocalName, aNodeName) { |
|
50 do_parse_check(aLocalName, "Missing element local name (endElement)"); |
|
51 do_parse_check(aNodeName, "Missing element node name (endElement)"); |
|
52 }, |
|
53 |
|
54 inCDataSection: false, |
|
55 |
|
56 characters: function characters(aData) { |
|
57 }, |
|
58 |
|
59 processingInstruction: function processingInstruction(aTarget, aData) { |
|
60 do_parse_check(aTarget, "Missing processing instruction target"); |
|
61 }, |
|
62 |
|
63 ignorableWhitespace: function ignorableWhitespace(aWhitespace) { |
|
64 }, |
|
65 |
|
66 startPrefixMapping: function startPrefixMapping(aPrefix, aURI) { |
|
67 }, |
|
68 |
|
69 endPrefixMapping: function endPrefixMapping(aPrefix) { |
|
70 } |
|
71 }; |
|
72 |
|
73 var lexicalHandler = { |
|
74 comment: function comment(aContents) { |
|
75 }, |
|
76 |
|
77 startDTD: function startDTD(aName, aPublicId, aSystemId) { |
|
78 do_parse_check(aName, "Missing DTD name"); |
|
79 }, |
|
80 |
|
81 endDTD: function endDTD() { |
|
82 }, |
|
83 |
|
84 startCDATA: function startCDATA() { |
|
85 }, |
|
86 |
|
87 endCDATA: function endCDATA() { |
|
88 }, |
|
89 |
|
90 startEntity: function startEntity(aName) { |
|
91 do_parse_check(aName, "Missing entity name (startEntity)"); |
|
92 }, |
|
93 |
|
94 endEntity: function endEntity(aName) { |
|
95 do_parse_check(aName, "Missing entity name (endEntity)"); |
|
96 } |
|
97 }; |
|
98 |
|
99 var dtdHandler = { |
|
100 notationDecl: function notationDecl(aName, aPublicId, aSystemId) { |
|
101 do_parse_check(aName, "Missing notation name"); |
|
102 }, |
|
103 |
|
104 unparsedEntityDecl: |
|
105 function unparsedEntityDecl(aName, aPublicId, aSystemId, aNotationName) { |
|
106 do_parse_check(aName, "Missing entity name (unparsedEntityDecl)"); |
|
107 } |
|
108 }; |
|
109 |
|
110 var errorHandler = { |
|
111 error: function error(aLocator, aError) { |
|
112 do_parse_check(!aError, "XML error"); |
|
113 }, |
|
114 |
|
115 fatalError: function fatalError(aLocator, aError) { |
|
116 do_parse_check(!aError, "XML fatal error"); |
|
117 }, |
|
118 |
|
119 ignorableWarning: function ignorableWarning(aLocator, aError) { |
|
120 do_parse_check(!aError, "XML ignorable warning"); |
|
121 } |
|
122 }; |
|
123 |
|
124 saxReader.contentHandler = contentHandler; |
|
125 saxReader.lexicalHandler = lexicalHandler; |
|
126 saxReader.dtdHandler = dtdHandler; |
|
127 saxReader.errorHandler = errorHandler; |
|
128 |
|
129 saxReader.parseFromString(source, "application/xml"); |
|
130 |
|
131 // Just in case it leaks. |
|
132 saxReader.contentHandler = null; |
|
133 saxReader.lexicalHandler = null; |
|
134 saxReader.dtdHandler = null; |
|
135 saxReader.errorHandler = null; |
|
136 |
|
137 return parseErrorLog; |
|
138 } |
|
139 |
|
140 function do_check_true_with_dump(aCondition, aParseLog) { |
|
141 if (!aCondition) { |
|
142 dump(aParseLog.join("\n")); |
|
143 } |
|
144 do_check_true(aCondition); |
|
145 } |
|
146 |
|
147 function run_test() { |
|
148 var src; |
|
149 src = "<!DOCTYPE foo>\n<!-- all your foo are belong to bar -->"; |
|
150 src += "<foo id='foo'>\n<?foo wooly bully?>\nfoo"; |
|
151 src += "<![CDATA[foo fighters]]></foo>\n"; |
|
152 var parseErrorLog = updateDocumentSourceMaps(src); |
|
153 |
|
154 if (parseErrorLog.length > 0) { |
|
155 dump(parseErrorLog.join("\n")); |
|
156 } |
|
157 do_check_true_with_dump(parseErrorLog.length == 0, parseErrorLog); |
|
158 |
|
159 // End tag isn't well-formed. |
|
160 src = "<!DOCTYPE foo>\n<!-- all your foo are belong to bar -->"; |
|
161 src += "<foo id='foo'>\n<?foo wooly bully?>\nfoo"; |
|
162 src += "<![CDATA[foo fighters]]></foo\n"; |
|
163 |
|
164 parseErrorLog = updateDocumentSourceMaps(src); |
|
165 |
|
166 do_check_true_with_dump(parseErrorLog.length == 1 && parseErrorLog[0] == "XML fatal error", parseErrorLog); |
|
167 } |