- * - * @author Sandy Gao, IBM - */ -public final class DOMMessageFormatter { - - public static final String DOM_DOMAIN = "http://www.w3.org/dom/DOMTR"; - - private static ResourceBundle DomResourceBundle_; - - /** - * Formats a message with the specified arguments. - * - * @param domain domain from which error string is to come. - * @param key The message key. - * @param arguments The message replacement text arguments. The order of the - * arguments must match that of the placeholders in the actual - * message. - * - * @return the formatted message. - * - * @throws MissingResourceException Thrown if the message with the specified key - * cannot be found. - */ - public static String formatMessage(final String domain, final String key, final Object[] arguments) throws MissingResourceException { - ResourceBundle resourceBundle = getResourceBundle(domain); - if (resourceBundle == null) { - init(); - resourceBundle = getResourceBundle(domain); - if (resourceBundle == null) { - throw new MissingResourceException("Unknown domain" + domain, null, key); - } - } - // format message - String msg; - try { - msg = key + ": " + resourceBundle.getString(key); - if (arguments != null) { - try { - msg = java.text.MessageFormat.format(msg, arguments); - } - catch (final Exception e) { - msg = resourceBundle.getString("FormatFailed"); - msg += " " + resourceBundle.getString(key); - } - } - } - catch (final MissingResourceException e) { - msg = resourceBundle.getString("BadMessageKey"); - throw new MissingResourceException(key, msg, key); - } - - // no message - if (msg == null) { - msg = key; - if (arguments.length > 0) { - final StringBuilder str = new StringBuilder(msg); - str.append('?'); - for (int i = 0; i < arguments.length; i++) { - if (i > 0) { - str.append('&'); - } - str.append(arguments[i]); - } - msg = str.toString(); - } - } - - return msg; - } - - static ResourceBundle getResourceBundle(final String domain) { - if (domain == DOM_DOMAIN || domain.equals(DOM_DOMAIN)) { - return DomResourceBundle_; - } - return null; - } - - /** - * Initialize Message Formatter. - */ - public static void init() { - DomResourceBundle_ = ResourceBundle.getBundle("org.htmlunit.cyberneko.xerces.impl.msg.DOMMessages"); - } - - private DOMMessageFormatter() { - } -} diff --git a/src/main/java/org/htmlunit/cyberneko/xerces/dom/DeepNodeListImpl.java b/src/main/java/org/htmlunit/cyberneko/xerces/dom/DeepNodeListImpl.java index 0416d8c0..0e2ad407 100644 --- a/src/main/java/org/htmlunit/cyberneko/xerces/dom/DeepNodeListImpl.java +++ b/src/main/java/org/htmlunit/cyberneko/xerces/dom/DeepNodeListImpl.java @@ -16,6 +16,7 @@ import java.util.ArrayList; +import org.htmlunit.cyberneko.util.StringUtils; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -187,14 +188,15 @@ else if (current != rootNode_ && null != (next = current.getNextSibling())) { // ("*" matches anything.) if (current != rootNode_ && current != null && current.getNodeType() == Node.ELEMENT_NODE) { if (!enableNS_) { - if ("*".equals(tagName_) || ((ElementImpl) current).getTagName().equals(tagName_)) { + if (StringUtils.equalsChar('*', tagName_) + || ((ElementImpl) current).getTagName().equalsIgnoreCase(tagName_)) { return current; } } else { // DOM2: Namespace logic. - if ("*".equals(tagName_)) { - if ("*".equals(nsName_)) { + if (StringUtils.equalsChar('*', tagName_)) { + if (StringUtils.equalsChar('*', nsName_)) { return current; } @@ -207,7 +209,7 @@ else if (current != rootNode_ && null != (next = current.getNextSibling())) { else { final ElementImpl el = (ElementImpl) current; if (el.getLocalName() != null && el.getLocalName().equals(tagName_)) { - if ("*".equals(nsName_)) { + if (StringUtils.equalsChar('*', nsName_)) { return current; } diff --git a/src/main/java/org/htmlunit/cyberneko/xerces/dom/DocumentImpl.java b/src/main/java/org/htmlunit/cyberneko/xerces/dom/DocumentImpl.java index 81ff60d7..4395ec9d 100644 --- a/src/main/java/org/htmlunit/cyberneko/xerces/dom/DocumentImpl.java +++ b/src/main/java/org/htmlunit/cyberneko/xerces/dom/DocumentImpl.java @@ -14,6 +14,7 @@ */ package org.htmlunit.cyberneko.xerces.dom; +import org.htmlunit.cyberneko.xerces.util.DOMMessageFormatter; import org.w3c.dom.Attr; import org.w3c.dom.DOMException; import org.w3c.dom.DOMImplementation; @@ -147,7 +148,7 @@ void insertedText(final CharacterDataImpl node, final int offset, final int coun */ @Override public Event createEvent(final String type) throws DOMException { - final String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + final String msg = DOMMessageFormatter.formatMessage("NOT_SUPPORTED_ERR", null); throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); } diff --git a/src/main/java/org/htmlunit/cyberneko/xerces/dom/ElementImpl.java b/src/main/java/org/htmlunit/cyberneko/xerces/dom/ElementImpl.java index 277e1cbc..6f0ca9a2 100644 --- a/src/main/java/org/htmlunit/cyberneko/xerces/dom/ElementImpl.java +++ b/src/main/java/org/htmlunit/cyberneko/xerces/dom/ElementImpl.java @@ -14,6 +14,7 @@ */ package org.htmlunit.cyberneko.xerces.dom; +import org.htmlunit.cyberneko.xerces.util.DOMMessageFormatter; import org.htmlunit.cyberneko.xerces.util.URI; import org.w3c.dom.Attr; import org.w3c.dom.DOMException; @@ -68,11 +69,11 @@ void rename(final String name) { if (ownerDocument.errorChecking) { final int colon1 = name.indexOf(':'); if (colon1 != -1) { - final String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null); + final String msg = DOMMessageFormatter.formatMessage("NAMESPACE_ERR", null); throw new DOMException(DOMException.NAMESPACE_ERR, msg); } if (!CoreDocumentImpl.isXMLName(name, ownerDocument.isXML11Version())) { - final String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null); + final String msg = DOMMessageFormatter.formatMessage("INVALID_CHARACTER_ERR", null); throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg); } } @@ -323,7 +324,7 @@ public void removeAttribute(final String name) { @Override public Attr removeAttributeNode(final Attr oldAttr) throws DOMException { if (attributes_ == null) { - final String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null); + final String msg = DOMMessageFormatter.formatMessage("NOT_FOUND_ERR", null); throw new DOMException(DOMException.NOT_FOUND_ERR, msg); } return (Attr) attributes_.removeItem(oldAttr); @@ -385,7 +386,7 @@ public void setAttribute(final String name, final String value) { public Attr setAttributeNode(final Attr newAttr) throws DOMException { if (ownerDocument.errorChecking) { if (newAttr.getOwnerDocument() != ownerDocument) { - final String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null); + final String msg = DOMMessageFormatter.formatMessage("WRONG_DOCUMENT_ERR", null); throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg); } } @@ -562,7 +563,7 @@ public Attr getAttributeNodeNS(final String namespaceURI, final String localName public Attr setAttributeNodeNS(final Attr newAttr) throws DOMException { if (ownerDocument.errorChecking) { if (newAttr.getOwnerDocument() != ownerDocument) { - final String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null); + final String msg = DOMMessageFormatter.formatMessage("WRONG_DOCUMENT_ERR", null); throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg); } } @@ -678,7 +679,7 @@ public boolean isEqualNode(final Node arg) { public void setIdAttributeNode(final Attr at, final boolean makeId) { if (ownerDocument.errorChecking) { if (at.getOwnerElement() != this) { - final String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null); + final String msg = DOMMessageFormatter.formatMessage("NOT_FOUND_ERR", null); throw new DOMException(DOMException.NOT_FOUND_ERR, msg); } } @@ -701,13 +702,13 @@ public void setIdAttribute(final String name, final boolean makeId) { final Attr at = getAttributeNode(name); if (at == null) { - final String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null); + final String msg = DOMMessageFormatter.formatMessage("NOT_FOUND_ERR", null); throw new DOMException(DOMException.NOT_FOUND_ERR, msg); } if (ownerDocument.errorChecking) { if (at.getOwnerElement() != this) { - final String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null); + final String msg = DOMMessageFormatter.formatMessage("NOT_FOUND_ERR", null); throw new DOMException(DOMException.NOT_FOUND_ERR, msg); } } @@ -731,13 +732,13 @@ public void setIdAttributeNS(final String namespaceURI, final String localName, final Attr at = getAttributeNodeNS(namespaceURI, localName); if (at == null) { - final String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null); + final String msg = DOMMessageFormatter.formatMessage("NOT_FOUND_ERR", null); throw new DOMException(DOMException.NOT_FOUND_ERR, msg); } if (ownerDocument.errorChecking) { if (at.getOwnerElement() != this) { - final String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null); + final String msg = DOMMessageFormatter.formatMessage("NOT_FOUND_ERR", null); throw new DOMException(DOMException.NOT_FOUND_ERR, msg); } } diff --git a/src/main/java/org/htmlunit/cyberneko/xerces/dom/ElementNSImpl.java b/src/main/java/org/htmlunit/cyberneko/xerces/dom/ElementNSImpl.java index cac07c7f..96e34758 100644 --- a/src/main/java/org/htmlunit/cyberneko/xerces/dom/ElementNSImpl.java +++ b/src/main/java/org/htmlunit/cyberneko/xerces/dom/ElementNSImpl.java @@ -14,6 +14,7 @@ */ package org.htmlunit.cyberneko.xerces.dom; +import org.htmlunit.cyberneko.xerces.util.DOMMessageFormatter; import org.htmlunit.cyberneko.xerces.xni.NamespaceContext; import org.w3c.dom.Attr; import org.w3c.dom.DOMException; @@ -65,7 +66,7 @@ private void setName(final String namespaceURI, final String qname) { // We dont need to check for namespaceURI != null, if qualified name is null // throw DOMException. if (qname == null) { - final String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null); + final String msg = DOMMessageFormatter.formatMessage("NAMESPACE_ERR", null); throw new DOMException(DOMException.NAMESPACE_ERR, msg); } @@ -81,7 +82,7 @@ private void setName(final String namespaceURI, final String qname) { if ("xmlns".equals(qname) && (namespaceURI == null || !namespaceURI.equals(NamespaceContext.XMLNS_URI)) || (namespaceURI != null && namespaceURI.equals(NamespaceContext.XMLNS_URI) && !"xmlns".equals(qname))) { - final String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null); + final String msg = DOMMessageFormatter.formatMessage("NAMESPACE_ERR", null); throw new DOMException(DOMException.NAMESPACE_ERR, msg); } } @@ -98,7 +99,7 @@ private void setName(final String namespaceURI, final String qname) { if (ownerDocument.errorChecking) { if (namespaceURI == null || ("xml".equals(prefix) && !namespaceURI.equals(NamespaceContext.XML_URI))) { - final String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null); + final String msg = DOMMessageFormatter.formatMessage("NAMESPACE_ERR", null); throw new DOMException(DOMException.NAMESPACE_ERR, msg); } @@ -187,16 +188,16 @@ public void setPrefix(final String prefix) throws DOMException { if (ownerDocument.errorChecking) { if (prefix != null && prefix.length() != 0) { if (!CoreDocumentImpl.isXMLName(prefix, ownerDocument.isXML11Version())) { - final String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_CHARACTER_ERR", null); + final String msg = DOMMessageFormatter.formatMessage("INVALID_CHARACTER_ERR", null); throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg); } if (namespaceURI == null || prefix.indexOf(':') >= 0) { - final String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null); + final String msg = DOMMessageFormatter.formatMessage("NAMESPACE_ERR", null); throw new DOMException(DOMException.NAMESPACE_ERR, msg); } else if ("xml".equals(prefix)) { if (!namespaceURI.equals(xmlURI)) { - final String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null); + final String msg = DOMMessageFormatter.formatMessage("NAMESPACE_ERR", null); throw new DOMException(DOMException.NAMESPACE_ERR, msg); } } diff --git a/src/main/java/org/htmlunit/cyberneko/xerces/dom/NamedNodeMapImpl.java b/src/main/java/org/htmlunit/cyberneko/xerces/dom/NamedNodeMapImpl.java index fbeab631..12cb4314 100644 --- a/src/main/java/org/htmlunit/cyberneko/xerces/dom/NamedNodeMapImpl.java +++ b/src/main/java/org/htmlunit/cyberneko/xerces/dom/NamedNodeMapImpl.java @@ -17,6 +17,7 @@ import java.util.List; import org.htmlunit.cyberneko.util.SimpleArrayList; +import org.htmlunit.cyberneko.xerces.util.DOMMessageFormatter; import org.w3c.dom.DOMException; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -157,7 +158,7 @@ public Node setNamedItem(final Node arg) throws DOMException { final CoreDocumentImpl ownerDocument = ownerNode.ownerDocument(); if (ownerDocument.errorChecking) { if (arg.getOwnerDocument() != ownerDocument) { - final String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null); + final String msg = DOMMessageFormatter.formatMessage("WRONG_DOCUMENT_ERR", null); throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg); } } @@ -190,7 +191,7 @@ public Node setNamedItemNS(final Node arg) throws DOMException { final CoreDocumentImpl ownerDocument = ownerNode.ownerDocument(); if (ownerDocument.errorChecking) { if (arg.getOwnerDocument() != ownerDocument) { - final String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null); + final String msg = DOMMessageFormatter.formatMessage("WRONG_DOCUMENT_ERR", null); throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg); } } @@ -236,7 +237,7 @@ public Node setNamedItemNS(final Node arg) throws DOMException { public Node removeNamedItem(final String name) throws DOMException { final int i = findNamePoint(name); if (i < 0) { - final String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null); + final String msg = DOMMessageFormatter.formatMessage("NOT_FOUND_ERR", null); throw new DOMException(DOMException.NOT_FOUND_ERR, msg); } @@ -254,7 +255,7 @@ public Node removeNamedItem(final String name) throws DOMException { public Node removeNamedItemNS(final String namespaceURI, final String name) throws DOMException { final int i = findNamePoint(namespaceURI, name); if (i < 0) { - final String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null); + final String msg = DOMMessageFormatter.formatMessage("NOT_FOUND_ERR", null); throw new DOMException(DOMException.NOT_FOUND_ERR, msg); } diff --git a/src/main/java/org/htmlunit/cyberneko/xerces/dom/NodeImpl.java b/src/main/java/org/htmlunit/cyberneko/xerces/dom/NodeImpl.java index 3a2c5618..d411d507 100644 --- a/src/main/java/org/htmlunit/cyberneko/xerces/dom/NodeImpl.java +++ b/src/main/java/org/htmlunit/cyberneko/xerces/dom/NodeImpl.java @@ -14,6 +14,7 @@ */ package org.htmlunit.cyberneko.xerces.dom; +import org.htmlunit.cyberneko.xerces.util.DOMMessageFormatter; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.DocumentType; @@ -410,7 +411,7 @@ public Node getLastChild() { @Override public Node insertBefore(final Node newChild, final Node refChild) throws DOMException { throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, - DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null)); + DOMMessageFormatter.formatMessage("HIERARCHY_REQUEST_ERR", null)); } /** @@ -430,7 +431,7 @@ public Node insertBefore(final Node newChild, final Node refChild) throws DOMExc @Override public Node removeChild(final Node oldChild) throws DOMException { throw new DOMException(DOMException.NOT_FOUND_ERR, - DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null)); + DOMMessageFormatter.formatMessage("NOT_FOUND_ERR", null)); } /** @@ -458,7 +459,7 @@ public Node removeChild(final Node oldChild) throws DOMException { @Override public Node replaceChild(final Node newChild, final Node oldChild) throws DOMException { throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, - DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null)); + DOMMessageFormatter.formatMessage("HIERARCHY_REQUEST_ERR", null)); } /** @@ -602,7 +603,7 @@ public String getPrefix() { @Override public void setPrefix(final String prefix) throws DOMException { throw new DOMException(DOMException.NAMESPACE_ERR, - DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NAMESPACE_ERR", null)); + DOMMessageFormatter.formatMessage("NAMESPACE_ERR", null)); } /** @@ -683,7 +684,7 @@ public short compareDocumentPosition(final Node other) throws DOMException { // check if other is from a different implementation if (other != null && !(other instanceof NodeImpl)) { // other comes from a different implementation - final String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_SUPPORTED_ERR", null); + final String msg = DOMMessageFormatter.formatMessage("NOT_SUPPORTED_ERR", null); throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg); } diff --git a/src/main/java/org/htmlunit/cyberneko/xerces/dom/ParentNode.java b/src/main/java/org/htmlunit/cyberneko/xerces/dom/ParentNode.java index 7a79d401..857e2225 100644 --- a/src/main/java/org/htmlunit/cyberneko/xerces/dom/ParentNode.java +++ b/src/main/java/org/htmlunit/cyberneko/xerces/dom/ParentNode.java @@ -14,6 +14,7 @@ */ package org.htmlunit.cyberneko.xerces.dom; +import org.htmlunit.cyberneko.xerces.util.DOMMessageFormatter; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Node; @@ -299,7 +300,7 @@ Node internalInsertBefore(final Node newChild, Node refChild, final boolean repl if (!ownerDocument.isKidOK(this, kid)) { throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, DOMMessageFormatter - .formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null)); + .formatMessage("HIERARCHY_REQUEST_ERR", null)); } } } @@ -325,16 +326,16 @@ Node internalInsertBefore(final Node newChild, Node refChild, final boolean repl if (errorChecking) { if (newChild.getOwnerDocument() != ownerDocument && newChild != ownerDocument) { throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, - DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "WRONG_DOCUMENT_ERR", null)); + DOMMessageFormatter.formatMessage("WRONG_DOCUMENT_ERR", null)); } if (!ownerDocument.isKidOK(this, newChild)) { throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, DOMMessageFormatter - .formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null)); + .formatMessage("HIERARCHY_REQUEST_ERR", null)); } // refChild must be a child of this node (or null) if (refChild != null && refChild.getParentNode() != this) { throw new DOMException(DOMException.NOT_FOUND_ERR, - DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null)); + DOMMessageFormatter.formatMessage("NOT_FOUND_ERR", null)); } // Prevent cycles in the tree @@ -346,7 +347,7 @@ Node internalInsertBefore(final Node newChild, Node refChild, final boolean repl } if (!treeSafe) { throw new DOMException(DOMException.HIERARCHY_REQUEST_ERR, DOMMessageFormatter - .formatMessage(DOMMessageFormatter.DOM_DOMAIN, "HIERARCHY_REQUEST_ERR", null)); + .formatMessage("HIERARCHY_REQUEST_ERR", null)); } } @@ -460,8 +461,7 @@ Node internalRemoveChild(final Node oldChild, final boolean replace) throws DOME final CoreDocumentImpl ownerDoc = ownerDocument(); if (ownerDoc.errorChecking) { if (oldChild != null && oldChild.getParentNode() != this) { - throw new DOMException(DOMException.NOT_FOUND_ERR, - DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NOT_FOUND_ERR", null)); + throw new DOMException(DOMException.NOT_FOUND_ERR, DOMMessageFormatter.formatMessage("NOT_FOUND_ERR", null)); } } diff --git a/src/main/java/org/htmlunit/cyberneko/xerces/dom/TextImpl.java b/src/main/java/org/htmlunit/cyberneko/xerces/dom/TextImpl.java index 0070c009..9d26a748 100644 --- a/src/main/java/org/htmlunit/cyberneko/xerces/dom/TextImpl.java +++ b/src/main/java/org/htmlunit/cyberneko/xerces/dom/TextImpl.java @@ -14,6 +14,7 @@ */ package org.htmlunit.cyberneko.xerces.dom; +import org.htmlunit.cyberneko.xerces.util.DOMMessageFormatter; import org.w3c.dom.DOMException; import org.w3c.dom.Node; import org.w3c.dom.Text; @@ -236,7 +237,7 @@ public Text replaceWholeText(final String content) throws DOMException { // make sure we can make the replacement if (!canModifyPrev(this) || !canModifyNext(this)) { throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, DOMMessageFormatter - .formatMessage(DOMMessageFormatter.DOM_DOMAIN, "NO_MODIFICATION_ALLOWED_ERR", null)); + .formatMessage("NO_MODIFICATION_ALLOWED_ERR", null)); } } @@ -495,8 +496,7 @@ private boolean hasTextOnlyChildren(final Node node) { @Override public Text splitText(final int offset) throws DOMException { if (offset < 0 || offset > data_.length()) { - throw new DOMException(DOMException.INDEX_SIZE_ERR, - DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INDEX_SIZE_ERR", null)); + throw new DOMException(DOMException.INDEX_SIZE_ERR, DOMMessageFormatter.formatMessage("INDEX_SIZE_ERR", null)); } // split text into two separate nodes diff --git a/src/main/java/org/htmlunit/cyberneko/xerces/parsers/AbstractDOMParser.java b/src/main/java/org/htmlunit/cyberneko/xerces/parsers/AbstractDOMParser.java index 57fcc22e..e14b703b 100644 --- a/src/main/java/org/htmlunit/cyberneko/xerces/parsers/AbstractDOMParser.java +++ b/src/main/java/org/htmlunit/cyberneko/xerces/parsers/AbstractDOMParser.java @@ -20,10 +20,9 @@ import org.htmlunit.cyberneko.xerces.dom.AttrImpl; import org.htmlunit.cyberneko.xerces.dom.CoreDocumentImpl; -import org.htmlunit.cyberneko.xerces.dom.DOMMessageFormatter; import org.htmlunit.cyberneko.xerces.dom.DocumentImpl; -import org.htmlunit.cyberneko.xerces.dom.EntityImpl; import org.htmlunit.cyberneko.xerces.dom.TextImpl; +import org.htmlunit.cyberneko.xerces.util.DOMMessageFormatter; import org.htmlunit.cyberneko.xerces.util.ErrorHandlerWrapper; import org.htmlunit.cyberneko.xerces.util.SAXMessageFormatter; import org.htmlunit.cyberneko.xerces.xni.Augmentations; @@ -110,7 +109,6 @@ public class AbstractDOMParser extends AbstractXMLDocumentParser { /** Current node. */ protected Node fCurrentNode; protected CDATASection fCurrentCDATASection; - protected EntityImpl fCurrentEntityDecl; /** Character buffer */ protected final XMLString fStringBuffer = new XMLString(); @@ -303,8 +301,7 @@ public void startDocument(final XMLLocator locator, final String encoding, final } } catch (final Exception e) { - throw new RuntimeException(DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, - "CannotCreateDocumentClass", new Object[] {fDocumentClass.getSimpleName()})); + throw new RuntimeException(DOMMessageFormatter.formatMessage("CannotCreateDocumentClass", new Object[] {fDocumentClass.getSimpleName()})); } } fCurrentNode = fDocument; diff --git a/src/main/java/org/htmlunit/cyberneko/xerces/parsers/AbstractSAXParser.java b/src/main/java/org/htmlunit/cyberneko/xerces/parsers/AbstractSAXParser.java index 18de1a14..7814dcd1 100644 --- a/src/main/java/org/htmlunit/cyberneko/xerces/parsers/AbstractSAXParser.java +++ b/src/main/java/org/htmlunit/cyberneko/xerces/parsers/AbstractSAXParser.java @@ -87,16 +87,16 @@ public abstract class AbstractSAXParser extends AbstractXMLDocumentParser implem // parser handlers /** Content handler. */ - protected ContentHandler fContentHandler; + private ContentHandler fContentHandler; /** Namespace context */ protected NamespaceContext fNamespaceContext; /** DTD handler. */ - protected org.xml.sax.DTDHandler fDTDHandler; + private org.xml.sax.DTDHandler fDTDHandler; /** Lexical handler. */ - protected LexicalHandler fLexicalHandler; + private LexicalHandler fLexicalHandler; // track the version of the document being parsed protected String fVersion; @@ -146,9 +146,7 @@ public void startDocument(final XMLLocator locator, final String encoding, final } // The application may have set the ContentHandler to null // within setDocumentLocator() so we need to check again. - if (fContentHandler != null) { - fContentHandler.startDocument(); - } + fContentHandler.startDocument(); } } catch (final SAXException e) { diff --git a/src/main/java/org/htmlunit/cyberneko/xerces/parsers/AbstractXMLDocumentParser.java b/src/main/java/org/htmlunit/cyberneko/xerces/parsers/AbstractXMLDocumentParser.java index fcd9a04a..287e3aa3 100644 --- a/src/main/java/org/htmlunit/cyberneko/xerces/parsers/AbstractXMLDocumentParser.java +++ b/src/main/java/org/htmlunit/cyberneko/xerces/parsers/AbstractXMLDocumentParser.java @@ -39,7 +39,6 @@ */ public abstract class AbstractXMLDocumentParser implements XMLDocumentHandler { - /** Property identifier: error handler. */ protected static final String ERROR_HANDLER = Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_HANDLER_PROPERTY; diff --git a/src/main/java/org/htmlunit/cyberneko/xerces/util/DOMMessageFormatter.java b/src/main/java/org/htmlunit/cyberneko/xerces/util/DOMMessageFormatter.java new file mode 100644 index 00000000..67a3ae71 --- /dev/null +++ b/src/main/java/org/htmlunit/cyberneko/xerces/util/DOMMessageFormatter.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2017-2024 Ronald Brill + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.htmlunit.cyberneko.xerces.util; + +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * Used to format DOM error messages. + *
+ *
+ * @author Sandy Gao, IBM
+ */
+public final class DOMMessageFormatter {
+
+ private static ResourceBundle DomResourceBundle_ = ResourceBundle.getBundle("org.htmlunit.cyberneko.res.DOMMessages");
+
+ private DOMMessageFormatter() {
+ }
+
+ /**
+ * Formats a message with the specified arguments.
+ *
+ * @param key The message key.
+ * @param arguments The message replacement text arguments. The order of the
+ * arguments must match that of the placeholders in the actual
+ * message.
+ *
+ * @return the formatted message.
+ *
+ * @throws MissingResourceException Thrown if the message with the specified key
+ * cannot be found.
+ */
+ public static String formatMessage(final String key, final Object[] arguments) throws MissingResourceException {
+ try {
+ String msg = key + ": " + DomResourceBundle_.getString(key);
+ if (arguments != null) {
+ try {
+ msg = java.text.MessageFormat.format(msg, arguments);
+ }
+ catch (final Exception e) {
+ msg = DomResourceBundle_.getString("FormatFailed");
+ msg += " " + DomResourceBundle_.getString(key);
+ }
+ }
+
+ return msg;
+ }
+ catch (final MissingResourceException e) {
+ final MissingResourceException mre = new MissingResourceException(key, DomResourceBundle_.getString("BadMessageKey"), key);
+ mre.initCause(e);
+ throw mre;
+ }
+ }
+}
diff --git a/src/main/java/org/htmlunit/cyberneko/xerces/util/SAXMessageFormatter.java b/src/main/java/org/htmlunit/cyberneko/xerces/util/SAXMessageFormatter.java
index 55912099..2ea3b4a3 100644
--- a/src/main/java/org/htmlunit/cyberneko/xerces/util/SAXMessageFormatter.java
+++ b/src/main/java/org/htmlunit/cyberneko/xerces/util/SAXMessageFormatter.java
@@ -24,6 +24,8 @@
*/
public final class SAXMessageFormatter {
+ private static final ResourceBundle SAXResourceBundle_ = ResourceBundle.getBundle("org.htmlunit.cyberneko.res.SAXMessages");
+
private SAXMessageFormatter() {
}
@@ -41,44 +43,24 @@ private SAXMessageFormatter() {
* cannot be found.
*/
public static String formatMessage(final String key, final Object[] arguments) throws MissingResourceException {
- final ResourceBundle resourceBundle = ResourceBundle.getBundle("org.htmlunit.cyberneko.xerces.impl.msg.SAXMessages");
-
- // format message
- String msg;
try {
- msg = resourceBundle.getString(key);
+ String msg = SAXResourceBundle_.getString(key);
if (arguments != null) {
try {
msg = java.text.MessageFormat.format(msg, arguments);
}
catch (final Exception e) {
- msg = resourceBundle.getString("FormatFailed");
- msg += " " + resourceBundle.getString(key);
+ msg = SAXResourceBundle_.getString("FormatFailed");
+ msg += " " + SAXResourceBundle_.getString(key);
}
}
- }
- // error
- catch (final MissingResourceException e) {
- msg = resourceBundle.getString("BadMessageKey");
- throw new MissingResourceException(key, msg, key);
+ return msg;
}
-
- // no message
- if (msg == null) {
- msg = key;
- if (arguments.length > 0) {
- final StringBuilder str = new StringBuilder(msg);
- str.append('?');
- for (int i = 0; i < arguments.length; i++) {
- if (i > 0) {
- str.append('&');
- }
- str.append(arguments[i]);
- }
- msg = str.toString();
- }
+ catch (final MissingResourceException e) {
+ final MissingResourceException mre = new MissingResourceException(key, SAXResourceBundle_.getString("BadMessageKey"), key);
+ mre.initCause(e);
+ throw mre;
}
- return msg;
}
}
diff --git a/src/main/java/org/htmlunit/cyberneko/xerces/util/URI.java b/src/main/java/org/htmlunit/cyberneko/xerces/util/URI.java
index 1772073c..a048d18d 100644
--- a/src/main/java/org/htmlunit/cyberneko/xerces/util/URI.java
+++ b/src/main/java/org/htmlunit/cyberneko/xerces/util/URI.java
@@ -745,7 +745,7 @@ private void initializeScheme(final String uriSpec) throws MalformedURIException
index++;
}
- String scheme = uriSpec.substring(0, index);
+ final String scheme = uriSpec.substring(0, index);
if (scheme.length() == 0) {
throw new MalformedURIException("No scheme found in URI.");
}
@@ -804,7 +804,7 @@ private boolean initializeAuthority(final String uriSpec) {
}
}
- String host = uriSpec.substring(start, index);
+ final String host = uriSpec.substring(start, index);
int port = -1;
if (host.length() > 0) {
// port
diff --git a/src/main/java/org/htmlunit/cyberneko/xerces/util/XMLAttributesImpl.java b/src/main/java/org/htmlunit/cyberneko/xerces/util/XMLAttributesImpl.java
index 4da70ef8..7bade23b 100644
--- a/src/main/java/org/htmlunit/cyberneko/xerces/util/XMLAttributesImpl.java
+++ b/src/main/java/org/htmlunit/cyberneko/xerces/util/XMLAttributesImpl.java
@@ -46,6 +46,21 @@ public XMLAttributesImpl() {
attributes_ = new ArrayList<>();
}
+ /** Copy constructor. */
+ public XMLAttributesImpl(final XMLAttributesImpl attributes) {
+ final ArrayListXNI
interface
+ * and compares it against the expected canonical output. Simple as that.
+ *
+ * @author Ronald Brill
+ */
+public class CanonicalXNITest extends AbstractCanonicalTest {
+
+ @ParameterizedTest
+ @MethodSource("testFiles")
+ public void runTest(final File dataFile) throws Exception {
+ final String domDataLines = getResult(dataFile);
+
+ try {
+ // prepare for future changes where canonical files are next to test file
+ File canonicalFile = new File(dataFile.getParentFile(), dataFile.getName() + ".canonical-xni");
+ if (!canonicalFile.exists()) {
+ canonicalFile = new File(canonicalDir, dataFile.getName() + ".canonical-xni");
+ }
+
+ if (!canonicalFile.exists()) {
+ fail("Canonical file not found for input: " + dataFile.getAbsolutePath() + ": " + domDataLines);
+ }
+
+ final File nyiFile = new File(canonicalFile.getParentFile(), canonicalFile.getName() + ".nyi");
+ if (nyiFile.exists()) {
+ try {
+ assertEquals(getCanonical(canonicalFile), domDataLines, dataFile.toString());
+ fail("test " + dataFile.getName() + "is marked as not yet implemented but already works");
+ }
+ catch (final AssertionFailedError e) {
+ // expected
+ }
+
+ assertEquals(getCanonical(nyiFile), domDataLines, "NYI: " + dataFile);
+ }
+ else {
+ assertEquals(getCanonical(canonicalFile), domDataLines, dataFile.toString());
+ }
+ }
+ catch (final AssertionFailedError e) {
+ String path = dataFile.getAbsolutePath();
+ path = path.substring(path.indexOf("\\testfiles\\") + 11);
+ final File output = new File(outputDir, path + ".canonical-xni");
+ Files.createDirectories(Paths.get(output.getParentFile().getPath()));
+ try (PrintWriter pw = new PrintWriter(Files.newOutputStream(output.toPath()))) {
+ pw.print(domDataLines);
+ }
+ throw e;
+ }
+ }
+
+ private static String getResult(final File infile) throws Exception {
+ try (StringWriter out = new StringWriter()) {
+
+ // parse
+ final XNIParser parser = new XNIParser(out);
+
+ HTMLConfiguration htmlConfiguration = new HTMLConfiguration();
+ htmlConfiguration.setFeature(HTMLConfiguration.AUGMENTATIONS, true);
+ htmlConfiguration.setDocumentHandler(parser);
+
+
+ final String normalized = getCanonical(infile);
+ htmlConfiguration.parse(new XMLInputSource(null, null, null, new StringReader(normalized), StandardCharsets.UTF_8.name()));
+
+ final StringBuilder sb = new StringBuilder();
+
+ // first the error handler output
+ final BufferedReader reader = new BufferedReader(new StringReader(out.toString()));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ sb.append(line).append('\n');
+ }
+
+ return sb.toString();
+ }
+ }
+
+ private static class XNIParser implements XMLDocumentHandler {
+ private StringWriter out_;
+
+ /** Default constructor. */
+ XNIParser(StringWriter out) {
+ out_ = out;
+ }
+
+ @Override
+ public void startDocument(XMLLocator locator, String encoding, NamespaceContext namespaceContext, Augmentations augs) throws XNIException {
+ out_.append("startDocument ");
+ appendAugmentations(augs);
+ out_.append('\n');
+ }
+
+ @Override
+ public void xmlDecl(String version, String encoding, String standalone, Augmentations augs) throws XNIException {
+ out_.append("xmlDecl ");
+ appendAugmentations(augs);
+ out_.append('\n');
+ }
+
+ @Override
+ public void doctypeDecl(String rootElement, String publicId, String systemId, Augmentations augs) throws XNIException {
+ out_.append("doctypeDecl ");
+ appendAugmentations(augs);
+ out_.append('\n');
+ }
+
+ @Override
+ public void comment(XMLString text, Augmentations augs) throws XNIException {
+ out_.append("comment '").append(text.toString()).append('\'');
+ appendAugmentations(augs);
+ out_.append('\n');
+ }
+
+ @Override
+ public void processingInstruction(String target, XMLString data, Augmentations augs) throws XNIException {
+ out_.append("processingInstruction ");
+ appendAugmentations(augs);
+ out_.append('\n');
+ }
+
+ @Override
+ public void startElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException {
+ out_.append("startElement (").append(element.toString()).append(") ");
+ appendAugmentations(augs);
+ out_.append('\n');
+ }
+
+ @Override
+ public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException {
+ out_.append("emptyElement (").append(element.toString()).append(") ");
+ appendAugmentations(augs);
+ out_.append('\n');
+ }
+
+ @Override
+ public void characters(XMLString text, Augmentations augs) throws XNIException {
+ out_.append("characters '").append(text.toString()).append('\'');
+ appendAugmentations(augs);
+ out_.append('\n');
+ }
+
+ @Override
+ public void endElement(QName element, Augmentations augs) throws XNIException {
+ out_.append("endElement (").append(element.toString()).append(") ");
+ appendAugmentations(augs);
+ out_.append('\n');
+ }
+
+ @Override
+ public void startCDATA(Augmentations augs) throws XNIException {
+ out_.append("startCDATA ");
+ appendAugmentations(augs);
+ out_.append('\n');
+ }
+
+ @Override
+ public void endCDATA(Augmentations augs) throws XNIException {
+ out_.append("endCDATA ");
+ appendAugmentations(augs);
+ out_.append('\n');
+ }
+
+ @Override
+ public void endDocument(Augmentations augs) throws XNIException {
+ out_.append("endDocument ");
+ appendAugmentations(augs);
+ out_.append('\n');
+ }
+
+ @Override
+ public void setDocumentSource(XMLDocumentSource source) {
+ }
+
+ @Override
+ public XMLDocumentSource getDocumentSource() {
+ return null;
+ }
+
+ private void appendAugmentations(final Augmentations augs) throws XNIException {
+ if (augs == null) {
+ out_.append("[no augs]");
+ return;
+ }
+
+ out_
+ .append("[(")
+ .append(Integer.toString(augs.getBeginLineNumber()))
+ .append(',')
+ .append(Integer.toString(augs.getBeginColumnNumber()))
+ .append(',')
+ .append(Integer.toString(augs.getBeginCharacterOffset()))
+ .append(") (")
+ .append(Integer.toString(augs.getEndLineNumber()))
+ .append(',')
+ .append(Integer.toString(augs.getEndColumnNumber()))
+ .append(',')
+ .append(Integer.toString(augs.getEndCharacterOffset()))
+ .append(") ")
+ .append(Boolean.toString(augs.isSynthesized()))
+ .append(']');
+ }
+ }
+}
diff --git a/src/test/java/org/htmlunit/cyberneko/DOMFragmentParserTest.java b/src/test/java/org/htmlunit/cyberneko/DOMFragmentParserTest.java
index d00b2da4..2f91e4fe 100644
--- a/src/test/java/org/htmlunit/cyberneko/DOMFragmentParserTest.java
+++ b/src/test/java/org/htmlunit/cyberneko/DOMFragmentParserTest.java
@@ -41,8 +41,8 @@ public class DOMFragmentParserTest {
* See Bug 154.
*/
@Test
- public void attrEndingWithCRAtEndOfStream() {
- // TODO doTest("");
+ public void attrEndingWithCRAtEndOfStream() throws Exception {
+ doTest("9 ?>", "");
+ doTest("9 ?>", "
hello\n -)NOFRAMES -(HEAD -)HEAD -(BODY -"\n -(P -"hello again\n -)P -)BODY -)HTML diff --git a/src/test/resources/org/htmlunit/cyberneko/testfiles/noframes/test-noframes.html.canonical-xni b/src/test/resources/org/htmlunit/cyberneko/testfiles/noframes/test-noframes.html.canonical-xni new file mode 100644 index 00000000..f514bd1c --- /dev/null +++ b/src/test/resources/org/htmlunit/cyberneko/testfiles/noframes/test-noframes.html.canonical-xni @@ -0,0 +1,21 @@ +startDocument [(1,1,0) (1,1,0) false] +startElement (localpart="html",rawname="html") [(1,1,0) (1,7,6) false] +startElement (localpart="noframes",rawname="noframes") [(2,1,7) (2,11,17) false] +characters ' +
hello
+'[(2,11,17) (4,1,27) false]
+endElement (localpart="noframes",rawname="noframes") [(4,1,27) (4,12,38) false]
+startElement (localpart="head",rawname="head",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+endElement (localpart="head",rawname="head",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+startElement (localpart="body",rawname="body") [(5,1,39) (5,7,45) false]
+characters '
+'[(5,7,45) (6,1,46) false]
+startElement (localpart="p",rawname="p") [(6,1,46) (6,4,49) false]
+characters 'hello again
+'[(6,4,49) (7,1,61) false]
+characters '
+'[(8,8,76) (9,1,77) false]
+endElement (localpart="p",rawname="p") [(-1,-1,-1) (-1,-1,-1) true]
+endElement (localpart="body",rawname="body") [(7,1,61) (7,8,68) false]
+endElement (localpart="html",rawname="html") [(8,1,69) (8,8,76) false]
+endDocument [(9,1,77) (9,1,77) false]
diff --git a/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test-attr-normalize-none.html.canonical-domhtml b/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test-attr-normalize-none.html.canonical-domhtml
deleted file mode 100644
index e44b31ee..00000000
--- a/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test-attr-normalize-none.html.canonical-domhtml
+++ /dev/null
@@ -1,17 +0,0 @@
-(HTML
-(HEAD
-)HEAD
-(BODY
-Aonload alert(1)\n// comment\nalert(2)
-"\n
-(DIV
-Aall 2s\t\t2t\n\n2n|2s
-Aleading-newline \n\n2n
-Aleading-space 2s
-Aleading-tab \t\t2t
-Atrailing-newline 2n\n\n
-Atrailing-space 2s
-Atrailing-tab 2t\t\t
-)DIV
-)BODY
-)HTML
diff --git a/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test-attr-normalize-none.html.canonical-xni b/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test-attr-normalize-none.html.canonical-xni
new file mode 100644
index 00000000..848de8fc
--- /dev/null
+++ b/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test-attr-normalize-none.html.canonical-xni
@@ -0,0 +1,14 @@
+startDocument [(1,1,0) (1,1,0) false]
+startElement (localpart="HTML",rawname="HTML",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+startElement (localpart="head",rawname="head",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+endElement (localpart="head",rawname="head",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+startElement (localpart="body",rawname="body") [(1,1,0) (3,11,44) false]
+characters '
+'[(3,11,44) (4,1,45) false]
+startElement (localpart="div",rawname="div") [(4,1,45) (16,10,230) false]
+characters '
+'[(16,10,230) (17,1,231) false]
+endElement (localpart="div",rawname="div") [(-1,-1,-1) (-1,-1,-1) true]
+endElement (localpart="body",rawname="body") [(-1,-1,-1) (-1,-1,-1) true]
+endElement (localpart="HTML",rawname="HTML",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+endDocument [(17,1,231) (17,1,231) false]
diff --git a/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test-attr-normalize.html.canonical-domhtml b/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test-attr-normalize.html.canonical-domhtml
deleted file mode 100644
index 5a455f18..00000000
--- a/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test-attr-normalize.html.canonical-domhtml
+++ /dev/null
@@ -1,17 +0,0 @@
-(HTML
-(HEAD
-)HEAD
-(BODY
-Aonload alert(1) // comment alert(2)
-"\n
-(DIV
-Aall 2s 2t 2n|2s
-Aleading-newline 2n
-Aleading-space 2s
-Aleading-tab 2t
-Atrailing-newline 2n
-Atrailing-space 2s
-Atrailing-tab 2t
-)DIV
-)BODY
-)HTML
diff --git a/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test-attr-normalize.html.canonical-xni b/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test-attr-normalize.html.canonical-xni
new file mode 100644
index 00000000..848de8fc
--- /dev/null
+++ b/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test-attr-normalize.html.canonical-xni
@@ -0,0 +1,14 @@
+startDocument [(1,1,0) (1,1,0) false]
+startElement (localpart="HTML",rawname="HTML",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+startElement (localpart="head",rawname="head",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+endElement (localpart="head",rawname="head",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+startElement (localpart="body",rawname="body") [(1,1,0) (3,11,44) false]
+characters '
+'[(3,11,44) (4,1,45) false]
+startElement (localpart="div",rawname="div") [(4,1,45) (16,10,230) false]
+characters '
+'[(16,10,230) (17,1,231) false]
+endElement (localpart="div",rawname="div") [(-1,-1,-1) (-1,-1,-1) true]
+endElement (localpart="body",rawname="body") [(-1,-1,-1) (-1,-1,-1) true]
+endElement (localpart="HTML",rawname="HTML",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+endDocument [(17,1,231) (17,1,231) false]
diff --git a/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test-empty-attr.html.canonical-domhtml b/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test-empty-attr.html.canonical-domhtml
deleted file mode 100644
index a1a30533..00000000
--- a/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test-empty-attr.html.canonical-domhtml
+++ /dev/null
@@ -1,10 +0,0 @@
-(HTML
-(HEAD
-)HEAD
-(BODY
-(P
-Astyle
-"Content
-)P
-)BODY
-)HTML
diff --git a/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test-empty-attr.html.canonical-xni b/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test-empty-attr.html.canonical-xni
new file mode 100644
index 00000000..cb40871e
--- /dev/null
+++ b/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test-empty-attr.html.canonical-xni
@@ -0,0 +1,13 @@
+startDocument [(1,1,0) (1,1,0) false]
+startElement (localpart="HTML",rawname="HTML",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+startElement (localpart="head",rawname="head",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+endElement (localpart="head",rawname="head",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+startElement (localpart="BODY",rawname="BODY",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+startElement (localpart="p",rawname="p") [(1,1,0) (1,13,12) false]
+characters 'Content'[(1,13,12) (1,20,19) false]
+endElement (localpart="p",rawname="p") [(1,20,19) (1,24,23) false]
+characters '
+'[(1,24,23) (2,1,24) false]
+endElement (localpart="BODY",rawname="BODY",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+endElement (localpart="HTML",rawname="HTML",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+endDocument [(2,1,24) (2,1,24) false]
diff --git a/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test061.html.canonical-domhtml b/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test061.html.canonical-domhtml
deleted file mode 100644
index d275629e..00000000
--- a/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test061.html.canonical-domhtml
+++ /dev/null
@@ -1,21 +0,0 @@
-(HTML
-(HEAD
-(META
-Acontent no-cache
-Ahttp-equiv Pragma
-)META
-"\n\n
-(TITLE
-"Title
-)TITLE
-"\n
-(META
-Acontent text/html; charset=iso-8859-1
-Ahttp-equiv Content-Type
-)META
-"\n
-)HEAD
-(BODY
-"\n
-)BODY
-)HTML
diff --git a/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test061.html.canonical-xni b/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test061.html.canonical-xni
new file mode 100644
index 00000000..6d1c0357
--- /dev/null
+++ b/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test061.html.canonical-xni
@@ -0,0 +1,25 @@
+startDocument [(1,1,0) (1,1,0) false]
+startElement (localpart="html",rawname="html") [(1,1,0) (1,7,6) false]
+startElement (localpart="HEAD",rawname="HEAD",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+emptyElement (localpart="meta",rawname="meta") [(2,1,7) (2,46,52) false]
+characters '
+'[(2,46,52) (3,1,53) false]
+characters '
+'[(3,7,59) (4,1,60) false]
+startElement (localpart="title",rawname="title") [(4,1,60) (4,8,67) false]
+characters 'Title'[(4,8,67) (4,13,72) false]
+endElement (localpart="title",rawname="title") [(4,13,72) (4,21,80) false]
+characters '
+'[(4,21,80) (5,1,81) false]
+emptyElement (localpart="meta",rawname="meta") [(5,1,81) (6,21,153) false]
+characters '
+'[(6,21,153) (7,1,154) false]
+endElement (localpart="HEAD",rawname="HEAD",uri="http://www.w3.org/1999/xhtml") [(7,1,154) (7,8,161) false]
+startElement (localpart="body",rawname="body") [(8,1,162) (8,7,168) false]
+characters '
+'[(8,7,168) (9,1,169) false]
+characters '
+'[(10,8,184) (11,1,185) false]
+endElement (localpart="body",rawname="body") [(9,1,169) (9,8,176) false]
+endElement (localpart="html",rawname="html") [(10,1,177) (10,8,184) false]
+endDocument [(11,1,185) (11,1,185) false]
diff --git a/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test081.html.canonical-domhtml b/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test081.html.canonical-domhtml
deleted file mode 100644
index f9310f86..00000000
--- a/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test081.html.canonical-domhtml
+++ /dev/null
@@ -1,13 +0,0 @@
-#one\ntwo\n\nthree\n\n\n
-?target one\ntwo\n\nthree\n\n\n
-(HTML
-Aattr one two three
-(HEAD
-)HEAD
-(BODY
-"\n[one\ntwo\n\nthree\n\n\n]\n
-(TEXTAREA
-"one\ntwo\n\nthree\n\n\n
-)TEXTAREA
-)BODY
-)HTML
diff --git a/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test081.html.canonical-xni b/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test081.html.canonical-xni
new file mode 100644
index 00000000..e51e94cf
--- /dev/null
+++ b/src/test/resources/org/htmlunit/cyberneko/testfiles/normalize-attrs/test081.html.canonical-xni
@@ -0,0 +1,36 @@
+startDocument [(1,1,0) (1,1,0) false]
+comment 'one
+two
+
+three
+
+
+'[(1,1,0) (7,4,24) false]
+processingInstruction [(8,1,25) (14,3,53) false]
+startElement (localpart="html",rawname="html") [(15,1,54) (21,3,85) false]
+startElement (localpart="head",rawname="head",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+endElement (localpart="head",rawname="head",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+startElement (localpart="body",rawname="body") [(22,1,86) (22,7,92) false]
+characters '
+[one
+two
+
+three
+
+
+]
+'[(22,7,92) (30,1,113) false]
+startElement (localpart="textarea",rawname="textarea") [(30,1,113) (30,11,123) false]
+characters 'one
+two
+
+three
+
+
+'[(30,11,123) (36,1,140) false]
+endElement (localpart="textarea",rawname="textarea") [(36,1,140) (36,12,151) false]
+characters '
+'[(36,12,151) (37,1,152) false]
+endElement (localpart="body",rawname="body") [(-1,-1,-1) (-1,-1,-1) true]
+endElement (localpart="html",rawname="html") [(-1,-1,-1) (-1,-1,-1) true]
+endDocument [(37,1,152) (37,1,152) false]
diff --git a/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-attribute.html.canonical-domhtml b/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-attribute.html.canonical-domhtml
deleted file mode 100644
index fa24a94f..00000000
--- a/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-attribute.html.canonical-domhtml
+++ /dev/null
@@ -1,12 +0,0 @@
-(HTML
-(HEAD
-)HEAD
-(BODY
-(DIV
-(NOSCRIPT
-"
-)DIV
-)BODY
-)HTML
diff --git a/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-attribute.html.canonical-xni b/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-attribute.html.canonical-xni
new file mode 100644
index 00000000..6811d1e2
--- /dev/null
+++ b/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-attribute.html.canonical-xni
@@ -0,0 +1,15 @@
+startDocument [(1,1,0) (1,1,0) false]
+startElement (localpart="HTML",rawname="HTML",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+startElement (localpart="head",rawname="head",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+endElement (localpart="head",rawname="head",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+startElement (localpart="BODY",rawname="BODY",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+startElement (localpart="div",rawname="div") [(1,1,0) (1,6,5) false]
+startElement (localpart="noscript",rawname="noscript") [(1,6,5) (1,16,15) false]
+emptyElement (localpart="link",rawname="link") [(1,16,15) (1,42,41) false]
+endElement (localpart="noscript",rawname="noscript") [(1,42,41) (1,53,52) false]
+characters '
+'[(1,53,52) (2,1,53) false]
+endElement (localpart="div",rawname="div") [(-1,-1,-1) (-1,-1,-1) true]
+endElement (localpart="BODY",rawname="BODY",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+endElement (localpart="HTML",rawname="HTML",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+endDocument [(2,1,53) (2,1,53) false]
diff --git a/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-comment.html.canonical-domhtml b/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-comment.html.canonical-domhtml
deleted file mode 100644
index a6212b61..00000000
--- a/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-comment.html.canonical-domhtml
+++ /dev/null
@@ -1,12 +0,0 @@
-(HTML
-(HEAD
-)HEAD
-(BODY
-(DIV
-(NOSCRIPT
-"
-)DIV
-)BODY
-)HTML
diff --git a/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-comment.html.canonical-xni b/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-comment.html.canonical-xni
new file mode 100644
index 00000000..ac484925
--- /dev/null
+++ b/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-comment.html.canonical-xni
@@ -0,0 +1,15 @@
+startDocument [(1,1,0) (1,1,0) false]
+startElement (localpart="HTML",rawname="HTML",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+startElement (localpart="head",rawname="head",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+endElement (localpart="head",rawname="head",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+startElement (localpart="BODY",rawname="BODY",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+startElement (localpart="div",rawname="div") [(1,1,0) (1,6,5) false]
+startElement (localpart="noscript",rawname="noscript") [(1,6,5) (1,16,15) false]
+comment ' '[(1,16,15) (1,36,35) false]
+endElement (localpart="noscript",rawname="noscript") [(1,36,35) (1,47,46) false]
+endElement (localpart="div",rawname="div") [(1,47,46) (1,53,52) false]
+characters '
+'[(1,53,52) (2,1,53) false]
+endElement (localpart="BODY",rawname="BODY",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+endElement (localpart="HTML",rawname="HTML",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+endDocument [(2,1,53) (2,1,53) false]
diff --git a/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-comment2.html.canonical-domhtml b/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-comment2.html.canonical-domhtml
deleted file mode 100644
index a6212b61..00000000
--- a/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-comment2.html.canonical-domhtml
+++ /dev/null
@@ -1,12 +0,0 @@
-(HTML
-(HEAD
-)HEAD
-(BODY
-(DIV
-(NOSCRIPT
-"
-)DIV
-)BODY
-)HTML
diff --git a/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-comment2.html.canonical-xni b/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-comment2.html.canonical-xni
new file mode 100644
index 00000000..8d9fb0ae
--- /dev/null
+++ b/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-comment2.html.canonical-xni
@@ -0,0 +1,15 @@
+startDocument [(1,1,0) (1,1,0) false]
+startElement (localpart="HTML",rawname="HTML",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+startElement (localpart="head",rawname="head",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+endElement (localpart="head",rawname="head",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+startElement (localpart="BODY",rawname="BODY",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+startElement (localpart="div",rawname="div") [(1,1,0) (1,6,5) false]
+startElement (localpart="noscript",rawname="noscript") [(1,6,5) (1,17,16) false]
+comment ' '[(1,17,16) (1,37,36) false]
+endElement (localpart="noscript",rawname="noscript") [(1,37,36) (1,48,47) false]
+endElement (localpart="div",rawname="div") [(1,48,47) (1,54,53) false]
+characters '
+'[(1,54,53) (2,1,54) false]
+endElement (localpart="BODY",rawname="BODY",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+endElement (localpart="HTML",rawname="HTML",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+endDocument [(2,1,54) (2,1,54) false]
diff --git a/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-comment3.html.canonical-domhtml b/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-comment3.html.canonical-domhtml
deleted file mode 100644
index 72523152..00000000
--- a/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-comment3.html.canonical-domhtml
+++ /dev/null
@@ -1,14 +0,0 @@
-(HTML
-(HEAD
-)HEAD
-(BODY
-(NOSCRIPT
-"
-)BODY
-)HTML
diff --git a/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-comment3.html.canonical-xni b/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-comment3.html.canonical-xni
new file mode 100644
index 00000000..0075f5cc
--- /dev/null
+++ b/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript-close-inside-comment3.html.canonical-xni
@@ -0,0 +1,11 @@
+startDocument [(1,1,0) (1,1,0) false]
+startElement (localpart="HTML",rawname="HTML",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+startElement (localpart="head",rawname="head",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+endElement (localpart="head",rawname="head",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+startElement (localpart="body",rawname="body") [(1,1,0) (1,7,6) false]
+startElement (localpart="noscript",rawname="noscript") [(1,7,6) (1,18,17) false]
+comment ''[(1,18,17) (1,62,61) false]
+endElement (localpart="noscript",rawname="noscript") [(-1,-1,-1) (-1,-1,-1) true]
+endElement (localpart="body",rawname="body") [(1,62,61) (1,69,68) false]
+endElement (localpart="HTML",rawname="HTML",uri="http://www.w3.org/1999/xhtml") [(-1,-1,-1) (-1,-1,-1) true]
+endDocument [(2,1,69) (2,1,69) false]
diff --git a/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript.html.canonical-domhtml b/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript.html.canonical-domhtml
deleted file mode 100644
index f999f51c..00000000
--- a/src/test/resources/org/htmlunit/cyberneko/testfiles/noscript/parse-noscript-content-false/test-noscript.html.canonical-domhtml
+++ /dev/null
@@ -1,9 +0,0 @@
-(HTML
-(HEAD
-(NOSCRIPT
-"