michael@0: function updateDocumentSourceMaps(source) {
michael@0: const nsIDOMNode = Components.interfaces.nsIDOMNode;
michael@0:
michael@0: const nsISAXXMLReader = Components.interfaces.nsISAXXMLReader;
michael@0: const saxReader = Components.classes["@mozilla.org/saxparser/xmlreader;1"]
michael@0: .createInstance(nsISAXXMLReader);
michael@0: try {
michael@0: saxReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
michael@0: saxReader.setFeature("http://xml.org/sax/features/namespace", true);
michael@0: }
michael@0: catch (e) {
michael@0: // do nothing, we'll accept it as it is.
michael@0: }
michael@0: var parseErrorLog = [];
michael@0:
michael@0: /* XXX ajvincent Because throwing an exception doesn't stop parsing, we need
michael@0: * to record errors and handle them after the parsing is finished.
michael@0: */
michael@0: function do_parse_check(aCondition, aMsg) {
michael@0: if (!aCondition)
michael@0: parseErrorLog[parseErrorLog.length] = aMsg;
michael@0: }
michael@0:
michael@0: var contentHandler = {
michael@0: startDocument: function startDocument() {
michael@0: },
michael@0:
michael@0: endDocument: function endDocument() {
michael@0: },
michael@0:
michael@0: handleAttributes: function handleAttributes(aAttributes) {
michael@0: for (var i = 0; i < aAttributes.length; i++) {
michael@0: var attrNamespaceURI = aAttributes.getURI(i);
michael@0: var attrLocalName = aAttributes.getLocalName(i);
michael@0: var attrNodeName = aAttributes.getQName(i);
michael@0: var value = aAttributes.getValue(i);
michael@0: do_parse_check(attrLocalName, "Missing attribute local name");
michael@0: do_parse_check(attrNodeName, "Missing attribute node name");
michael@0: }
michael@0: },
michael@0:
michael@0: startElement: function startElement(aNamespaceURI, aLocalName, aNodeName, aAttributes) {
michael@0: do_parse_check(aLocalName, "Missing element local name (startElement)");
michael@0: do_parse_check(aNodeName, "Missing element node name (startElement)");
michael@0: do_parse_check(aAttributes, "Missing element attributes");
michael@0: this.handleAttributes(aAttributes);
michael@0: },
michael@0:
michael@0: endElement: function endElement(aNamespaceURI, aLocalName, aNodeName) {
michael@0: do_parse_check(aLocalName, "Missing element local name (endElement)");
michael@0: do_parse_check(aNodeName, "Missing element node name (endElement)");
michael@0: },
michael@0:
michael@0: inCDataSection: false,
michael@0:
michael@0: characters: function characters(aData) {
michael@0: },
michael@0:
michael@0: processingInstruction: function processingInstruction(aTarget, aData) {
michael@0: do_parse_check(aTarget, "Missing processing instruction target");
michael@0: },
michael@0:
michael@0: ignorableWhitespace: function ignorableWhitespace(aWhitespace) {
michael@0: },
michael@0:
michael@0: startPrefixMapping: function startPrefixMapping(aPrefix, aURI) {
michael@0: },
michael@0:
michael@0: endPrefixMapping: function endPrefixMapping(aPrefix) {
michael@0: }
michael@0: };
michael@0:
michael@0: var lexicalHandler = {
michael@0: comment: function comment(aContents) {
michael@0: },
michael@0:
michael@0: startDTD: function startDTD(aName, aPublicId, aSystemId) {
michael@0: do_parse_check(aName, "Missing DTD name");
michael@0: },
michael@0:
michael@0: endDTD: function endDTD() {
michael@0: },
michael@0:
michael@0: startCDATA: function startCDATA() {
michael@0: },
michael@0:
michael@0: endCDATA: function endCDATA() {
michael@0: },
michael@0:
michael@0: startEntity: function startEntity(aName) {
michael@0: do_parse_check(aName, "Missing entity name (startEntity)");
michael@0: },
michael@0:
michael@0: endEntity: function endEntity(aName) {
michael@0: do_parse_check(aName, "Missing entity name (endEntity)");
michael@0: }
michael@0: };
michael@0:
michael@0: var dtdHandler = {
michael@0: notationDecl: function notationDecl(aName, aPublicId, aSystemId) {
michael@0: do_parse_check(aName, "Missing notation name");
michael@0: },
michael@0:
michael@0: unparsedEntityDecl:
michael@0: function unparsedEntityDecl(aName, aPublicId, aSystemId, aNotationName) {
michael@0: do_parse_check(aName, "Missing entity name (unparsedEntityDecl)");
michael@0: }
michael@0: };
michael@0:
michael@0: var errorHandler = {
michael@0: error: function error(aLocator, aError) {
michael@0: do_parse_check(!aError, "XML error");
michael@0: },
michael@0:
michael@0: fatalError: function fatalError(aLocator, aError) {
michael@0: do_parse_check(!aError, "XML fatal error");
michael@0: },
michael@0:
michael@0: ignorableWarning: function ignorableWarning(aLocator, aError) {
michael@0: do_parse_check(!aError, "XML ignorable warning");
michael@0: }
michael@0: };
michael@0:
michael@0: saxReader.contentHandler = contentHandler;
michael@0: saxReader.lexicalHandler = lexicalHandler;
michael@0: saxReader.dtdHandler = dtdHandler;
michael@0: saxReader.errorHandler = errorHandler;
michael@0:
michael@0: saxReader.parseFromString(source, "application/xml");
michael@0:
michael@0: // Just in case it leaks.
michael@0: saxReader.contentHandler = null;
michael@0: saxReader.lexicalHandler = null;
michael@0: saxReader.dtdHandler = null;
michael@0: saxReader.errorHandler = null;
michael@0:
michael@0: return parseErrorLog;
michael@0: }
michael@0:
michael@0: function do_check_true_with_dump(aCondition, aParseLog) {
michael@0: if (!aCondition) {
michael@0: dump(aParseLog.join("\n"));
michael@0: }
michael@0: do_check_true(aCondition);
michael@0: }
michael@0:
michael@0: function run_test() {
michael@0: var src;
michael@0: src = "\n";
michael@0: src += "\n\nfoo";
michael@0: src += "\n";
michael@0: var parseErrorLog = updateDocumentSourceMaps(src);
michael@0:
michael@0: if (parseErrorLog.length > 0) {
michael@0: dump(parseErrorLog.join("\n"));
michael@0: }
michael@0: do_check_true_with_dump(parseErrorLog.length == 0, parseErrorLog);
michael@0:
michael@0: // End tag isn't well-formed.
michael@0: src = "\n";
michael@0: src += "\n\nfoo";
michael@0: src += "