From: <bo...@us...> - 2010-09-03 13:40:47
|
Revision: 457 http://xmlunit.svn.sourceforge.net/xmlunit/?rev=457&view=rev Author: bodewig Date: 2010-09-03 13:40:40 +0000 (Fri, 03 Sep 2010) Log Message: ----------- ignoring whitespace Modified Paths: -------------- trunk/xmlunit/src/main/java-core/net/sf/xmlunit/util/Nodes.java trunk/xmlunit/src/main/java-legacy/org/custommonkey/xmlunit/Diff.java trunk/xmlunit/src/main/java-legacy/org/custommonkey/xmlunit/NewDifferenceEngine.java trunk/xmlunit/src/main/net-core/util/Nodes.cs trunk/xmlunit/src/tests/java-core/net/sf/xmlunit/util/NodesTest.java trunk/xmlunit/src/tests/net-core/util/NodesTest.cs Added Paths: ----------- trunk/xmlunit/src/main/java-core/net/sf/xmlunit/input/WhitespaceStrippedSource.java trunk/xmlunit/src/main/net-core/input/WhitespaceStrippedSource.cs Added: trunk/xmlunit/src/main/java-core/net/sf/xmlunit/input/WhitespaceStrippedSource.java =================================================================== --- trunk/xmlunit/src/main/java-core/net/sf/xmlunit/input/WhitespaceStrippedSource.java (rev 0) +++ trunk/xmlunit/src/main/java-core/net/sf/xmlunit/input/WhitespaceStrippedSource.java 2010-09-03 13:40:40 UTC (rev 457) @@ -0,0 +1,31 @@ +/* + This file is licensed to You 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 + + http://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 net.sf.xmlunit.input; + +import javax.xml.transform.Source; +import javax.xml.transform.dom.DOMSource; +import net.sf.xmlunit.util.Convert; +import net.sf.xmlunit.util.Nodes; + +/** + * A source that is obtained from a different source by removing all + * empty text nodes and trimming the non-empty ones. + */ +public class WhitespaceStrippedSource extends DOMSource { + + public WhitespaceStrippedSource(Source originalSource) { + super(Nodes.stripWhitespace(Convert.toDocument(originalSource))); + setSystemId(originalSource.getSystemId()); + } +} Property changes on: trunk/xmlunit/src/main/java-core/net/sf/xmlunit/input/WhitespaceStrippedSource.java ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/xmlunit/src/main/java-core/net/sf/xmlunit/util/Nodes.java =================================================================== --- trunk/xmlunit/src/main/java-core/net/sf/xmlunit/util/Nodes.java 2010-09-03 08:41:54 UTC (rev 456) +++ trunk/xmlunit/src/main/java-core/net/sf/xmlunit/util/Nodes.java 2010-09-03 13:40:40 UTC (rev 457) @@ -13,14 +13,18 @@ */ package net.sf.xmlunit.util; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; import java.util.Map; -import java.util.LinkedHashMap; import javax.xml.XMLConstants; import javax.xml.namespace.QName; import org.w3c.dom.Attr; import org.w3c.dom.CDATASection; +import org.w3c.dom.CharacterData; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; import org.w3c.dom.Text; /** @@ -77,4 +81,46 @@ } return map; } + + /** + * Creates a new Node (of the same type as the original node) that + * is similar to the orginal but doesn't contain any empty text or + * CDATA nodes and where all textual content including attribute + * values or comments are trimmed. + */ + public static Node stripWhitespace(Node original) { + Node cloned = original.cloneNode(true); + cloned.normalize(); + stripWsRec(cloned); + return cloned; + } + + /** + * Trims textual content of this node, removes empty text and + * CDATA children, recurses into its child nodes. + */ + private static void stripWsRec(Node n) { + if (n instanceof CharacterData || n instanceof ProcessingInstruction) { + n.setNodeValue(n.getNodeValue().trim()); + } + List<Node> toRemove = new LinkedList<Node>(); + for (Node child : new IterableNodeList(n.getChildNodes())) { + stripWsRec(child); + if (!(n instanceof Attr) + && (child instanceof Text || child instanceof CDATASection) + && child.getNodeValue().length() == 0) { + toRemove.add(child); + } + } + for (Node child : toRemove) { + n.removeChild(child); + } + NamedNodeMap attrs = n.getAttributes(); + if (attrs != null) { + final int len = attrs.getLength(); + for (int i = 0; i < len; i++) { + stripWsRec(attrs.item(i)); + } + } + } } Modified: trunk/xmlunit/src/main/java-legacy/org/custommonkey/xmlunit/Diff.java =================================================================== --- trunk/xmlunit/src/main/java-legacy/org/custommonkey/xmlunit/Diff.java 2010-09-03 08:41:54 UTC (rev 456) +++ trunk/xmlunit/src/main/java-legacy/org/custommonkey/xmlunit/Diff.java 2010-09-03 13:40:40 UTC (rev 457) @@ -1,6 +1,6 @@ /* ****************************************************************** -Copyright (c) 2001-2008, Jeff Martin, Tim Bacon +Copyright (c) 2001-2008,2010 Jeff Martin, Tim Bacon All rights reserved. Redistribution and use in source and binary forms, with or without @@ -422,8 +422,6 @@ && !XMLUnit.getNormalizeWhitespace() && - !XMLUnit.getIgnoreWhitespace() - && !usesUnknownElementQualifier() ) { return new NewDifferenceEngine(this, matchTrackerDelegate); Modified: trunk/xmlunit/src/main/java-legacy/org/custommonkey/xmlunit/NewDifferenceEngine.java =================================================================== --- trunk/xmlunit/src/main/java-legacy/org/custommonkey/xmlunit/NewDifferenceEngine.java 2010-09-03 08:41:54 UTC (rev 456) +++ trunk/xmlunit/src/main/java-legacy/org/custommonkey/xmlunit/NewDifferenceEngine.java 2010-09-03 13:40:40 UTC (rev 457) @@ -48,6 +48,7 @@ import net.sf.xmlunit.diff.DifferenceEvaluators; import net.sf.xmlunit.diff.ElementSelector; import net.sf.xmlunit.input.CommentLessSource; +import net.sf.xmlunit.input.WhitespaceStrippedSource; import org.w3c.dom.CDATASection; import org.w3c.dom.Comment; @@ -150,6 +151,10 @@ ctrlSource = new CommentLessSource(ctrlSource); tstSource = new CommentLessSource(tstSource); } + if (XMLUnit.getIgnoreWhitespace()) { + ctrlSource = new WhitespaceStrippedSource(ctrlSource); + tstSource = new WhitespaceStrippedSource(tstSource); + } engine.compare(ctrlSource, tstSource); } Added: trunk/xmlunit/src/main/net-core/input/WhitespaceStrippedSource.cs =================================================================== --- trunk/xmlunit/src/main/net-core/input/WhitespaceStrippedSource.cs (rev 0) +++ trunk/xmlunit/src/main/net-core/input/WhitespaceStrippedSource.cs 2010-09-03 13:40:40 UTC (rev 457) @@ -0,0 +1,29 @@ +/* + This file is licensed to You 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 + + http://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. +*/ + +using net.sf.xmlunit.util; + +namespace net.sf.xmlunit.input { + + /// <summary> + /// A source that is obtained from a different source by removing + /// all empty text nodes and trimming the non-empty ones. + /// </summary> + public class WhitespaceStrippedSource : DOMSource { + public WhitespaceStrippedSource(ISource originalSource) : + base(Nodes.StripWhitespace(Convert.ToDocument(originalSource))) { + SystemId = originalSource.SystemId; + } + } +} Property changes on: trunk/xmlunit/src/main/net-core/input/WhitespaceStrippedSource.cs ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/xmlunit/src/main/net-core/util/Nodes.cs =================================================================== --- trunk/xmlunit/src/main/net-core/util/Nodes.cs 2010-09-03 08:41:54 UTC (rev 456) +++ trunk/xmlunit/src/main/net-core/util/Nodes.cs 2010-09-03 13:40:40 UTC (rev 457) @@ -64,5 +64,47 @@ } return map; } + + /// <summary> + /// Creates a new Node (of the same type as the original node) + /// that is similar to the orginal but doesn't contain any + /// empty text or CDATA nodes and where all textual content + /// including attribute values or comments are trimmed. + /// </summary> + public static XmlNode StripWhitespace(XmlNode original) { + XmlNode cloned = original.CloneNode(true); + cloned.Normalize(); + StripWsRec(cloned); + return cloned; + } + + /// <summary> + /// Trims textual content of this node, removes empty text and + /// CDATA children, recurses into its child nodes. + /// </summary> + private static void StripWsRec(XmlNode n) { + if (n is XmlCharacterData || n is XmlProcessingInstruction) { + n.Value = n.Value.Trim(); + } + LinkedList<XmlNode> toRemove = new LinkedList<XmlNode>(); + foreach (XmlNode child in n.ChildNodes) { + StripWsRec(child); + if (!(n is XmlAttribute) + && (child is XmlText || child is XmlCDataSection) + && child.Value.Length == 0) { + toRemove.AddLast(child); + } + } + foreach (XmlNode child in toRemove) { + n.RemoveChild(child); + } + XmlNamedNodeMap attrs = n.Attributes; + if (attrs != null) { + foreach (XmlAttribute a in attrs) { + StripWsRec(a); + } + } + } + } } Modified: trunk/xmlunit/src/tests/java-core/net/sf/xmlunit/util/NodesTest.java =================================================================== --- trunk/xmlunit/src/tests/java-core/net/sf/xmlunit/util/NodesTest.java 2010-09-03 08:41:54 UTC (rev 456) +++ trunk/xmlunit/src/tests/java-core/net/sf/xmlunit/util/NodesTest.java 2010-09-03 13:40:40 UTC (rev 457) @@ -13,18 +13,24 @@ */ package net.sf.xmlunit.util; +import java.util.AbstractMap; import java.util.Map; import javax.xml.XMLConstants; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; +import net.sf.xmlunit.builder.Input; import org.junit.Before; import org.junit.Test; +import org.w3c.dom.Attr; import org.w3c.dom.CDATASection; import org.w3c.dom.Comment; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.ProcessingInstruction; import org.w3c.dom.Text; import static org.junit.Assert.*; @@ -138,4 +144,106 @@ assertEquals(BAR, m.get(new QName(SOME_URI, FOO))); assertEquals(BAR, m.get(new QName(SOME_URI, FOO, BAR))); } + + private Map.Entry<Document, Node> stripWsSetup() { + Document toTest = Convert.toDocument(Input.fromMemory( + "<root>\n" + + "<!-- trim me -->\n" + + "<child attr=' trim me ' attr2='not me'>\n" + + " trim me \n" + + "</child><![CDATA[ trim me ]]>\n" + + "<?target trim me ?>\n" + + "<![CDATA[ ]]>\n" + + "</root>").build()); + return new AbstractMap.SimpleImmutableEntry(toTest, + Nodes.stripWhitespace(toTest)); + } + + @Test public void stripWhitespaceWorks() { + Map.Entry<Document, Node> s = stripWsSetup(); + assertTrue(s.getValue() instanceof Document); + NodeList top = s.getValue().getChildNodes(); + assertEquals(1, top.getLength()); + assertTrue(top.item(0) instanceof Element); + assertEquals("root", top.item(0).getNodeName()); + NodeList rootsChildren = top.item(0).getChildNodes(); + assertEquals(4, rootsChildren.getLength()); + assertTrue("should be comment, is " + rootsChildren.item(0).getClass(), + rootsChildren.item(0) instanceof Comment); + assertEquals("trim me", ((Comment) rootsChildren.item(0)).getData()); + assertTrue("should be element, is " + rootsChildren.item(1).getClass(), + rootsChildren.item(1) instanceof Element); + assertEquals("child", rootsChildren.item(1).getNodeName()); + assertTrue("should be cdata, is " + rootsChildren.item(2).getClass(), + rootsChildren.item(2) instanceof CDATASection); + assertEquals("trim me", + ((CDATASection) rootsChildren.item(2)).getData()); + assertTrue("should be PI, is " + rootsChildren.item(3).getClass(), + rootsChildren.item(3) instanceof ProcessingInstruction); + assertEquals("trim me", + ((ProcessingInstruction) rootsChildren.item(3)).getData()); + Node child = rootsChildren.item(1); + NodeList grandChildren = child.getChildNodes(); + assertEquals(1, grandChildren.getLength()); + assertTrue("should be text, is " + grandChildren.item(0).getClass(), + grandChildren.item(0) instanceof Text); + assertEquals("trim me", ((Text) grandChildren.item(0)).getData()); + NamedNodeMap attrs = child.getAttributes(); + assertEquals(2, attrs.getLength()); + Attr a = (Attr) attrs.getNamedItem("attr"); + assertEquals("trim me", a.getValue()); + Attr a2 = (Attr) attrs.getNamedItem("attr2"); + assertEquals("not me", a2.getValue()); + } + + @Test public void stripWhitespaceDoesntAlterOriginal() { + Map.Entry<Document, Node> s = stripWsSetup(); + NodeList top = s.getKey().getChildNodes(); + assertEquals(1, top.getLength()); + assertTrue(top.item(0) instanceof Element); + assertEquals("root", top.item(0).getNodeName()); + NodeList rootsChildren = top.item(0).getChildNodes(); + assertEquals(10, rootsChildren.getLength()); + assertNewlineTextNode(rootsChildren.item(0)); + assertTrue("should be comment, is " + rootsChildren.item(1).getClass(), + rootsChildren.item(1) instanceof Comment); + assertEquals(" trim me ", ((Comment) rootsChildren.item(1)).getData()); + assertNewlineTextNode(rootsChildren.item(2)); + assertTrue("should be element, is " + rootsChildren.item(3).getClass(), + rootsChildren.item(3) instanceof Element); + assertEquals("child", rootsChildren.item(3).getNodeName()); + assertTrue("should be cdata, is " + rootsChildren.item(4).getClass(), + rootsChildren.item(4) instanceof CDATASection); + assertEquals(" trim me ", + ((CDATASection) rootsChildren.item(4)).getData()); + assertNewlineTextNode(rootsChildren.item(5)); + assertTrue("should be PI, is " + rootsChildren.item(6).getClass(), + rootsChildren.item(6) instanceof ProcessingInstruction); + assertEquals("trim me ", + ((ProcessingInstruction) rootsChildren.item(6)).getData()); + assertNewlineTextNode(rootsChildren.item(7)); + assertTrue("should be cdata, is " + rootsChildren.item(8).getClass(), + rootsChildren.item(8) instanceof CDATASection); + assertEquals(" ", + ((CDATASection) rootsChildren.item(8)).getData()); + assertNewlineTextNode(rootsChildren.item(9)); + Node child = rootsChildren.item(3); + NodeList grandChildren = child.getChildNodes(); + assertEquals(1, grandChildren.getLength()); + assertTrue("should be text, is " + grandChildren.item(0).getClass(), + grandChildren.item(0) instanceof Text); + assertEquals("\n trim me \n", ((Text) grandChildren.item(0)).getData()); + NamedNodeMap attrs = child.getAttributes(); + assertEquals(2, attrs.getLength()); + Attr a = (Attr) attrs.getNamedItem("attr"); + assertEquals(" trim me ", a.getValue()); + Attr a2 = (Attr) attrs.getNamedItem("attr2"); + assertEquals("not me", a2.getValue()); + } + + private static void assertNewlineTextNode(Node n) { + assertTrue("should be text, is " + n.getClass(), + n instanceof Text); + assertEquals("\n", ((Text) n).getData()); + } } Modified: trunk/xmlunit/src/tests/net-core/util/NodesTest.cs =================================================================== --- trunk/xmlunit/src/tests/net-core/util/NodesTest.cs 2010-09-03 08:41:54 UTC (rev 456) +++ trunk/xmlunit/src/tests/net-core/util/NodesTest.cs 2010-09-03 13:40:40 UTC (rev 457) @@ -15,6 +15,7 @@ using System.Collections.Generic; using System.Xml; using NUnit.Framework; +using net.sf.xmlunit.builder; namespace net.sf.xmlunit.util { [TestFixture] @@ -121,5 +122,100 @@ Assert.AreEqual(1, m.Count); Assert.AreEqual(BAR, m[new XmlQualifiedName(FOO, SOME_URI)]); } + + private KeyValuePair<XmlDocument, XmlNode> StripWsSetup() { + XmlDocument toTest = Convert.ToDocument(Input.FromMemory( + "<root>\n" + + "<!-- trim me -->\n" + + "<child attr=' trim me ' attr2='not me'>\n" + + " trim me \n" + + "</child><![CDATA[ trim me ]]>\n" + + "<?target trim me ?>\n" + + "<![CDATA[ ]]>\n" + + "</root>").Build()); + return new KeyValuePair<XmlDocument, + XmlNode>(toTest, Nodes.StripWhitespace(toTest)); + } + + [Test] + public void StripWhitespaceWorks() { + KeyValuePair<XmlDocument, XmlNode> s = StripWsSetup(); + Assert.IsTrue(s.Value is XmlDocument); + XmlNodeList top = s.Value.ChildNodes; + Assert.AreEqual(1, top.Count); + Assert.IsTrue(top[0] is XmlElement); + Assert.AreEqual("root", top[0].Name); + XmlNodeList rootsChildren = top[0].ChildNodes; + Assert.AreEqual(4, rootsChildren.Count); + Assert.IsTrue(rootsChildren[0] is XmlComment, + "should be comment, is " + rootsChildren[0].GetType()); + Assert.AreEqual("trim me", + ((XmlComment) rootsChildren[0]).Data); + Assert.IsTrue(rootsChildren[1] is XmlElement, + "should be element, is " + rootsChildren[1].GetType()); + Assert.AreEqual("child", rootsChildren[1].Name); + Assert.IsTrue(rootsChildren[2] is XmlCDataSection, + "should be cdata, is " + rootsChildren[2].GetType()); + Assert.AreEqual("trim me", + ((XmlCDataSection) rootsChildren[2]).Data); + Assert.IsTrue(rootsChildren[3] is XmlProcessingInstruction, + "should be PI, is " + rootsChildren[3].GetType()); + Assert.AreEqual("trim me", + ((XmlProcessingInstruction) rootsChildren[3]).Data); + XmlNode child = rootsChildren[1]; + XmlNodeList grandChildren = child.ChildNodes; + Assert.AreEqual(1, grandChildren.Count); + Assert.IsTrue(grandChildren[0] is XmlText, + "should be text, is " + grandChildren[0].GetType()); + Assert.AreEqual("trim me", ((XmlText) grandChildren[0]).Data); + XmlNamedNodeMap attrs = child.Attributes; + Assert.AreEqual(2, attrs.Count); + XmlAttribute a = (XmlAttribute) attrs.GetNamedItem("attr"); + Assert.AreEqual("trim me", a.Value); + XmlAttribute a2 = (XmlAttribute) attrs.GetNamedItem("attr2"); + Assert.AreEqual("not me", a2.Value); + } + + [Test] + public void StripWhitespaceDoesntAlterOriginal() { + KeyValuePair<XmlDocument, XmlNode> s = StripWsSetup(); + XmlNodeList top = s.Key.ChildNodes; + Assert.AreEqual(1, top.Count); + Assert.IsTrue(top[0] is XmlElement); + Assert.AreEqual("root", top[0].Name); + XmlNodeList rootsChildren = top[0].ChildNodes; + Assert.AreEqual(5, rootsChildren.Count); + Assert.IsTrue(rootsChildren[0] is XmlComment, + "should be comment, is " + rootsChildren[0].GetType()); + Assert.AreEqual(" trim me ", + ((XmlComment) rootsChildren[0]).Data); + Assert.IsTrue(rootsChildren[1] is XmlElement, + "should be element, is " + rootsChildren[1].GetType()); + Assert.AreEqual("child", rootsChildren[1].Name); + Assert.IsTrue(rootsChildren[2] is XmlCDataSection, + "should be cdata, is " + rootsChildren[2].GetType()); + Assert.AreEqual(" trim me ", + ((XmlCDataSection) rootsChildren[2]).Data); + Assert.IsTrue(rootsChildren[3] is XmlProcessingInstruction, + "should be PI, is " + rootsChildren[3].GetType()); + Assert.AreEqual("trim me ", + ((XmlProcessingInstruction) rootsChildren[3]).Data); + Assert.IsTrue(rootsChildren[4] is XmlCDataSection, + "should be cdata, is " + rootsChildren[4].GetType()); + Assert.AreEqual(" ", + ((XmlCDataSection) rootsChildren[4]).Data); + XmlNode child = rootsChildren[1]; + XmlNodeList grandChildren = child.ChildNodes; + Assert.AreEqual(1, grandChildren.Count); + Assert.IsTrue(grandChildren[0] is XmlText, + "should be text, is " + grandChildren[0].GetType()); + Assert.AreEqual("\n trim me \n", ((XmlText) grandChildren[0]).Data); + XmlNamedNodeMap attrs = child.Attributes; + Assert.AreEqual(2, attrs.Count); + XmlAttribute a = (XmlAttribute) attrs.GetNamedItem("attr"); + Assert.AreEqual(" trim me ", a.Value); + XmlAttribute a2 = (XmlAttribute) attrs.GetNamedItem("attr2"); + Assert.AreEqual("not me", a2.Value); + } } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |