From: <bo...@us...> - 2010-08-20 10:07:55
|
Revision: 432 http://xmlunit.svn.sourceforge.net/xmlunit/?rev=432&view=rev Author: bodewig Date: 2010-08-20 10:07:48 +0000 (Fri, 20 Aug 2010) Log Message: ----------- prepare for XPath tracking in difference engine Modified Paths: -------------- trunk/xmlunit/src/main/java-core/net/sf/xmlunit/diff/AbstractDifferenceEngine.java trunk/xmlunit/src/main/java-core/net/sf/xmlunit/diff/DifferenceEngine.java trunk/xmlunit/src/main/net-core/diff/AbstractDifferenceEngine.cs trunk/xmlunit/src/main/net-core/diff/IDifferenceEngine.cs Added Paths: ----------- trunk/xmlunit/src/main/java-core/net/sf/xmlunit/diff/XPathContext.java trunk/xmlunit/src/main/net-core/diff/XPathContext.cs trunk/xmlunit/src/tests/java-core/net/sf/xmlunit/diff/XPathContextTest.java trunk/xmlunit/src/tests/net-core/diff/XPathContextTest.cs Modified: trunk/xmlunit/src/main/java-core/net/sf/xmlunit/diff/AbstractDifferenceEngine.java =================================================================== --- trunk/xmlunit/src/main/java-core/net/sf/xmlunit/diff/AbstractDifferenceEngine.java 2010-08-19 14:52:28 UTC (rev 431) +++ trunk/xmlunit/src/main/java-core/net/sf/xmlunit/diff/AbstractDifferenceEngine.java 2010-08-20 10:07:48 UTC (rev 432) @@ -13,6 +13,9 @@ */ package net.sf.xmlunit.diff; +import java.util.Collections; +import java.util.Map; + /** * Useful base-implementation of some parts of the DifferenceEngine * interface. @@ -22,6 +25,7 @@ new ComparisonListenerSupport(); private ElementSelector elementSelector = ElementSelectors.Default; private DifferenceEvaluator diffEvaluator = DifferenceEvaluators.Default; + private Map<String, String> uri2Prefix = Collections.emptyMap(); public void addComparisonListener(ComparisonListener l) { if (l == null) { @@ -68,6 +72,10 @@ return diffEvaluator; } + public void setNamespaceContext(Map<String, String> uri2Prefix) { + this.uri2Prefix = Collections.unmodifiableMap(uri2Prefix); + } + /** * Compares the detail values for object equality, lets the * difference evaluator evaluate the result, notifies all Modified: trunk/xmlunit/src/main/java-core/net/sf/xmlunit/diff/DifferenceEngine.java =================================================================== --- trunk/xmlunit/src/main/java-core/net/sf/xmlunit/diff/DifferenceEngine.java 2010-08-19 14:52:28 UTC (rev 431) +++ trunk/xmlunit/src/main/java-core/net/sf/xmlunit/diff/DifferenceEngine.java 2010-08-20 10:07:48 UTC (rev 432) @@ -13,6 +13,7 @@ */ package net.sf.xmlunit.diff; +import java.util.Map; import javax.xml.transform.Source; /** @@ -48,6 +49,18 @@ void setDifferenceEvaluator(DifferenceEvaluator e); /** + * Establish a namespace context that will be used in {@link + * Comparison.Detail#getXPath Comparison.Detail#getXPath}. + * + * <p>Without a namespace context (or with an empty context) the + * XPath expressions will only use local names for elements and + * attributes.</p> + * + * @param uri2Prefix maps from namespace URI to prefix. + */ + void setNamespaceContext(Map<String, String> uri2Prefix); + + /** * Compares two pieces of XML and invokes the registered listeners. */ void compare(Source control, Source test); Added: trunk/xmlunit/src/main/java-core/net/sf/xmlunit/diff/XPathContext.java =================================================================== --- trunk/xmlunit/src/main/java-core/net/sf/xmlunit/diff/XPathContext.java (rev 0) +++ trunk/xmlunit/src/main/java-core/net/sf/xmlunit/diff/XPathContext.java 2010-08-20 10:07:48 UTC (rev 432) @@ -0,0 +1,148 @@ +/* + 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.diff; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Deque; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import javax.xml.namespace.QName; +import net.sf.xmlunit.util.Nodes; +import org.w3c.dom.Node; + +public class XPathContext { + private final Deque<Level> path = new LinkedList<Level>(); + private final Map<String, String> uri2Prefix; + + public XPathContext() { + this(null); + } + + public XPathContext(Map<String, String> uri2Prefix) { + if (uri2Prefix == null) { + this.uri2Prefix = Collections.emptyMap(); + } else { + this.uri2Prefix = Collections.unmodifiableMap(uri2Prefix); + } + path.addLast(new Level("")); + } + + public void navigateToChild(int index) { + path.addLast(path.getLast().children.get(index)); + } + + public void navigateToAttribute(QName attribute) { + path.addLast(path.getLast().attributes.get(attribute)); + } + + public void navigateToParent() { + path.removeLast(); + } + + public void registerAttributes(Iterable<? extends QName> attributes) { + Level current = path.getLast(); + for (QName attribute : attributes) { + current.attributes.put(attribute, + new Level("@" + getName(attribute))); + } + } + + public void registerChildren(Iterable<? extends NodeInfo> children) { + Level current = path.getLast(); + int comments, pis, texts; + comments = pis = texts = 0; + Map<String, Integer> elements = new HashMap<String, Integer>(); + for (NodeInfo child : children) { + Level l = null; + switch (child.getType()) { + case Node.COMMENT_NODE: + l = new Level("comment()[" + (++comments) + "]"); + break; + case Node.PROCESSING_INSTRUCTION_NODE: + l = new Level("processing-instruction()[" + (++pis) + "]"); + break; + case Node.CDATA_SECTION_NODE: + case Node.TEXT_NODE: + l = new Level("text()[" + (++texts) + "]"); + break; + case Node.ELEMENT_NODE: + String name = getName(child.getName()); + Integer old = elements.get(name); + int index = old == null ? 0 : old.intValue(); + l = new Level(name + "[" + (++index) + "]"); + elements.put(name, Integer.valueOf(index)); + break; + default: + throw new IllegalArgumentException("unknown node type " + + child.getType()); + } + current.children.add(l); + } + } + + public String getXPath() { + StringBuilder sb = new StringBuilder(); + boolean first = true, second = false; + for (Level l : path) { + if (!second) { + sb.append("/"); + } + sb.append(l.expression); + if (first) { + second = true; + } else { + second = false; + } + first = false; + } + return sb.toString(); + } + + private String getName(QName name) { + String ns = name.getNamespaceURI(); + String p = null; + if (ns != null) { + p = uri2Prefix.get(ns); + } + return (p == null ? "" : p + ":") + name.getLocalPart(); + } + + private static class Level { + private final String expression; + private List<Level> children = new ArrayList<Level>(); + private Map<QName, Level> attributes = new HashMap<QName, Level>(); + private Level(String expression) { + this.expression = expression; + } + } + + public static interface NodeInfo { + QName getName(); + short getType(); + } + + public static final class DOMNodeInfo implements NodeInfo { + private QName name; + private short type; + public DOMNodeInfo(Node n) { + name = Nodes.getQName(n); + type = n.getNodeType(); + } + public QName getName() { return name; } + public short getType() { return type; } + } +} Property changes on: trunk/xmlunit/src/main/java-core/net/sf/xmlunit/diff/XPathContext.java ___________________________________________________________________ Added: svn:eol-style + native Modified: trunk/xmlunit/src/main/net-core/diff/AbstractDifferenceEngine.cs =================================================================== --- trunk/xmlunit/src/main/net-core/diff/AbstractDifferenceEngine.cs 2010-08-19 14:52:28 UTC (rev 431) +++ trunk/xmlunit/src/main/net-core/diff/AbstractDifferenceEngine.cs 2010-08-20 10:07:48 UTC (rev 432) @@ -13,6 +13,7 @@ */ using System; +using System.Collections.Generic; namespace net.sf.xmlunit.diff { @@ -53,6 +54,14 @@ public abstract void Compare(ISource control, ISource test); + private IDictionary<string, string> namespaceContext; + + public IDictionary<string, string> NamespaceContext { + set { + namespaceContext = value; + } + } + /// <summary> /// Compares the detail values for object equality, lets the /// difference evaluator evaluate the result, notifies all Modified: trunk/xmlunit/src/main/net-core/diff/IDifferenceEngine.cs =================================================================== --- trunk/xmlunit/src/main/net-core/diff/IDifferenceEngine.cs 2010-08-19 14:52:28 UTC (rev 431) +++ trunk/xmlunit/src/main/net-core/diff/IDifferenceEngine.cs 2010-08-20 10:07:48 UTC (rev 432) @@ -12,6 +12,8 @@ limitations under the License. */ +using System.Collections.Generic; + namespace net.sf.xmlunit.diff { /// <summary> @@ -47,6 +49,17 @@ DifferenceEvaluator DifferenceEvaluator { set; } /// <summary> + /// Establish a namespace context mapping from URI to prefix + /// that will be used in Comparison.Detail.XPath. + /// </summary> + /// <remarks> + /// Without a namespace context (or with an empty context) the + /// XPath expressions will only use local names for elements and + /// attributes. + /// </remarks> + IDictionary<string, string> NamespaceContext { set; } + + /// <summary> /// Compares two pieces of XML and invokes the registered listeners. /// </summary> void Compare(ISource control, ISource test); Added: trunk/xmlunit/src/main/net-core/diff/XPathContext.cs =================================================================== --- trunk/xmlunit/src/main/net-core/diff/XPathContext.cs (rev 0) +++ trunk/xmlunit/src/main/net-core/diff/XPathContext.cs 2010-08-20 10:07:48 UTC (rev 432) @@ -0,0 +1,150 @@ +/* + 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 System; +using System.Collections.Generic; +using System.Text; +using System.Xml; +using net.sf.xmlunit.util; + +namespace net.sf.xmlunit.diff { + public class XPathContext { + private readonly LinkedList<Level> path = new LinkedList<Level>(); + private readonly IDictionary<string, string> uri2Prefix; + + public XPathContext() : this(null) { + } + + public XPathContext(IDictionary<string, string> uri2Prefix) { + if (uri2Prefix == null) { + this.uri2Prefix = new Dictionary<string, string>(); + } else { + this.uri2Prefix = new Dictionary<string, string>(uri2Prefix); + } + path.AddLast(new Level("")); + } + + public void NavigateToChild(int index) { + path.AddLast(path.Last.Value.Children[index]); + } + + public void NavigateToAttribute(XmlQualifiedName attribute) { + path.AddLast(path.Last.Value.Attributes[attribute]); + } + + public void NavigateToParent() { + path.RemoveLast(); + } + + public void RegisterAttributes<Q>(IEnumerable<Q> attributes) + where Q : XmlQualifiedName { + Level current = path.Last.Value; + foreach (XmlQualifiedName attribute in attributes) { + current.Attributes[attribute] = + new Level("@" + GetName(attribute)); + } + } + + public void RegisterChildren<N>(IEnumerable<N> children) + where N : INodeInfo { + Level current = path.Last.Value; + int comments, pis, texts; + comments = pis = texts = 0; + IDictionary<string, int> elements = new Dictionary<string, int>(); + foreach (INodeInfo child in children) { + Level l = null; + switch (child.Type) { + case XmlNodeType.Comment: + l = new Level("comment()[" + (++comments) + "]"); + break; + case XmlNodeType.ProcessingInstruction: + l = new Level("processing-instruction()[" + (++pis) + "]"); + break; + case XmlNodeType.CDATA: + case XmlNodeType.Text: + l = new Level("text()[" + (++texts) + "]"); + break; + case XmlNodeType.Element: + string name = GetName(child.Name); + int old; + if (!elements.TryGetValue(name, out old)) { + old = 0; + } + l = new Level(name + "[" + (++old) + "]"); + elements[name] = old; + break; + default: + throw new ArgumentException("unknown node type " + + child.Type); + } + current.Children.Add(l); + } + } + + public string XPath { + get { + StringBuilder sb = new StringBuilder(); + bool first = true, second = false; + foreach (Level l in path) { + if (!second) { + sb.Append("/"); + } + sb.Append(l.Expression); + if (first) { + second = true; + } else { + second = false; + } + first = false; + } + return sb.ToString(); + } + } + + private string GetName(XmlQualifiedName name) { + string ns = name.Namespace; + string p = null; + if (ns != null) { + uri2Prefix.TryGetValue(ns, out p); + } + return (p == null ? "" : p + ":") + name.Name; + } + + internal class Level { + internal readonly string Expression; + internal readonly IList<Level> Children = new List<Level>(); + internal readonly IDictionary<XmlQualifiedName, Level> Attributes = + new Dictionary<XmlQualifiedName, Level>(); + internal Level(string expression) { + this.Expression = expression; + } + } + + public interface INodeInfo { + XmlQualifiedName Name { get; } + XmlNodeType Type { get; } + } + + public class DOMNodeInfo : INodeInfo { + private XmlQualifiedName name; + private XmlNodeType type; + public DOMNodeInfo(XmlNode n) { + name = Nodes.GetQName(n); + type = n.NodeType; + } + public XmlQualifiedName Name { get { return name; } } + public XmlNodeType Type { get { return type; } } + } + } +} \ No newline at end of file Property changes on: trunk/xmlunit/src/main/net-core/diff/XPathContext.cs ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/xmlunit/src/tests/java-core/net/sf/xmlunit/diff/XPathContextTest.java =================================================================== --- trunk/xmlunit/src/tests/java-core/net/sf/xmlunit/diff/XPathContextTest.java (rev 0) +++ trunk/xmlunit/src/tests/java-core/net/sf/xmlunit/diff/XPathContextTest.java 2010-08-20 10:07:48 UTC (rev 432) @@ -0,0 +1,185 @@ +/* + 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.diff; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import javax.xml.namespace.QName; +import org.junit.Test; +import org.w3c.dom.Node; + +import static org.junit.Assert.*; + +public class XPathContextTest { + @Test public void empty() { + assertEquals("/", new XPathContext().getXPath()); + } + + @Test public void oneLevelOfElements() { + ArrayList<Element> l = new ArrayList<Element>(); + l.add(new Element("foo")); + l.add(new Element("foo")); + l.add(new Element("bar")); + l.add(new Element("foo")); + XPathContext ctx = new XPathContext(); + ctx.registerChildren(l); + ctx.navigateToChild(0); + assertEquals("/foo[1]", ctx.getXPath()); + ctx.navigateToParent(); + ctx.navigateToChild(1); + assertEquals("/foo[2]", ctx.getXPath()); + ctx.navigateToParent(); + ctx.navigateToChild(2); + assertEquals("/bar[1]", ctx.getXPath()); + ctx.navigateToParent(); + ctx.navigateToChild(3); + assertEquals("/foo[3]", ctx.getXPath()); + } + + @Test public void twoLevelsOfElements() { + ArrayList<Element> l = new ArrayList<Element>(); + l.add(new Element("foo")); + l.add(new Element("foo")); + l.add(new Element("bar")); + l.add(new Element("foo")); + XPathContext ctx = new XPathContext(); + ctx.registerChildren(l); + ctx.navigateToChild(0); + assertEquals("/foo[1]", ctx.getXPath()); + ctx.registerChildren(l); + ctx.navigateToChild(3); + assertEquals("/foo[1]/foo[3]", ctx.getXPath()); + ctx.navigateToParent(); + assertEquals("/foo[1]", ctx.getXPath()); + ctx.navigateToParent(); + ctx.navigateToChild(2); + assertEquals("/bar[1]", ctx.getXPath()); + } + + @Test public void attributes() { + XPathContext ctx = new XPathContext(); + ctx.registerChildren(Collections.singletonList(new Element("foo"))); + ctx.navigateToChild(0); + ArrayList<QName> l = new ArrayList<QName>(); + l.add(new QName("bar")); + ctx.registerAttributes(l); + ctx.navigateToAttribute(new QName("bar")); + assertEquals("/foo[1]/@bar", ctx.getXPath()); + } + + @Test public void mixed() { + ArrayList<XPathContext.NodeInfo> l = new ArrayList<XPathContext.NodeInfo>(); + l.add(new Text()); + l.add(new Comment()); + l.add(new CDATA()); + l.add(new PI()); + l.add(new CDATA()); + l.add(new Comment()); + l.add(new PI()); + l.add(new Text()); + XPathContext ctx = new XPathContext(); + ctx.registerChildren(l); + ctx.navigateToChild(0); + assertEquals("/text()[1]", ctx.getXPath()); + ctx.navigateToParent(); + ctx.navigateToChild(1); + assertEquals("/comment()[1]", ctx.getXPath()); + ctx.navigateToParent(); + ctx.navigateToChild(2); + assertEquals("/text()[2]", ctx.getXPath()); + ctx.navigateToParent(); + ctx.navigateToChild(3); + assertEquals("/processing-instruction()[1]", ctx.getXPath()); + ctx.navigateToParent(); + ctx.navigateToChild(4); + assertEquals("/text()[3]", ctx.getXPath()); + ctx.navigateToParent(); + ctx.navigateToChild(5); + assertEquals("/comment()[2]", ctx.getXPath()); + ctx.navigateToParent(); + ctx.navigateToChild(6); + assertEquals("/processing-instruction()[2]", ctx.getXPath()); + ctx.navigateToParent(); + ctx.navigateToChild(7); + assertEquals("/text()[4]", ctx.getXPath()); + } + + @Test public void elementsAndNs() { + ArrayList<Element> l = new ArrayList<Element>(); + l.add(new Element("foo", "urn:foo:foo")); + l.add(new Element("foo")); + l.add(new Element("foo", "urn:foo:bar")); + HashMap<String, String> m = new HashMap<String, String>(); + m.put("urn:foo:bar", "bar"); + XPathContext ctx = new XPathContext(m); + ctx.registerChildren(l); + ctx.navigateToChild(0); + assertEquals("/foo[1]", ctx.getXPath()); + ctx.navigateToParent(); + ctx.navigateToChild(1); + assertEquals("/foo[2]", ctx.getXPath()); + ctx.navigateToParent(); + ctx.navigateToChild(2); + assertEquals("/bar:foo[1]", ctx.getXPath()); + } + + @Test public void attributesAndNs() { + HashMap<String, String> m = new HashMap<String, String>(); + m.put("urn:foo:bar", "bar"); + XPathContext ctx = new XPathContext(m); + ctx.registerChildren(Collections.singletonList(new Element("foo", + "urn:foo:bar")) + ); + ctx.navigateToChild(0); + ArrayList<QName> l = new ArrayList<QName>(); + l.add(new QName("baz")); + l.add(new QName("urn:foo:bar", "baz")); + ctx.registerAttributes(l); + ctx.navigateToAttribute(new QName("baz")); + assertEquals("/bar:foo[1]/@baz", ctx.getXPath()); + ctx.navigateToParent(); + ctx.navigateToAttribute(new QName("urn:foo:bar", "baz")); + assertEquals("/bar:foo[1]/@bar:baz", ctx.getXPath()); + ctx.navigateToParent(); + } + + private static class Element implements XPathContext.NodeInfo { + private final QName name; + private Element(String name) { + this.name = new QName(name); + } + private Element(String name, String ns) { + this.name = new QName(ns, name); + } + public QName getName() { return name; } + public short getType() { return Node.ELEMENT_NODE; } + } + + private static abstract class NonElement implements XPathContext.NodeInfo { + public QName getName() { return null; } + } + private static class Text extends NonElement { + public short getType() { return Node.TEXT_NODE; } + } + private static class Comment extends NonElement { + public short getType() { return Node.COMMENT_NODE; } + } + private static class PI extends NonElement { + public short getType() { return Node.PROCESSING_INSTRUCTION_NODE; } + } + private static class CDATA extends NonElement { + public short getType() { return Node.CDATA_SECTION_NODE; } + } +} \ No newline at end of file Property changes on: trunk/xmlunit/src/tests/java-core/net/sf/xmlunit/diff/XPathContextTest.java ___________________________________________________________________ Added: svn:eol-style + native Added: trunk/xmlunit/src/tests/net-core/diff/XPathContextTest.cs =================================================================== --- trunk/xmlunit/src/tests/net-core/diff/XPathContextTest.cs (rev 0) +++ trunk/xmlunit/src/tests/net-core/diff/XPathContextTest.cs 2010-08-20 10:07:48 UTC (rev 432) @@ -0,0 +1,201 @@ +/* + 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 System; +using System.Collections.Generic; +using System.Xml; +using NUnit.Framework; + +namespace net.sf.xmlunit.diff { + + [TestFixture] + public class XPathContextTest { + [Test] + public void Empty() { + Assert.AreEqual("/", new XPathContext().XPath); + } + + [Test] + public void OneLevelOfElements() { + List<Element> l = new List<Element>(); + l.Add(new Element("foo")); + l.Add(new Element("foo")); + l.Add(new Element("bar")); + l.Add(new Element("foo")); + XPathContext ctx = new XPathContext(); + ctx.RegisterChildren(l); + ctx.NavigateToChild(0); + Assert.AreEqual("/foo[1]", ctx.XPath); + ctx.NavigateToParent(); + ctx.NavigateToChild(1); + Assert.AreEqual("/foo[2]", ctx.XPath); + ctx.NavigateToParent(); + ctx.NavigateToChild(2); + Assert.AreEqual("/bar[1]", ctx.XPath); + ctx.NavigateToParent(); + ctx.NavigateToChild(3); + Assert.AreEqual("/foo[3]", ctx.XPath); + } + + [Test] + public void TwoLevelsOfElements() { + List<Element> l = new List<Element>(); + l.Add(new Element("foo")); + l.Add(new Element("foo")); + l.Add(new Element("bar")); + l.Add(new Element("foo")); + XPathContext ctx = new XPathContext(); + ctx.RegisterChildren(l); + ctx.NavigateToChild(0); + Assert.AreEqual("/foo[1]", ctx.XPath); + ctx.RegisterChildren(l); + ctx.NavigateToChild(3); + Assert.AreEqual("/foo[1]/foo[3]", ctx.XPath); + ctx.NavigateToParent(); + Assert.AreEqual("/foo[1]", ctx.XPath); + ctx.NavigateToParent(); + ctx.NavigateToChild(2); + Assert.AreEqual("/bar[1]", ctx.XPath); + } + + [Test] + public void Attributes() { + XPathContext ctx = new XPathContext(); + ctx.RegisterChildren(Singleton(new Element("foo"))); + ctx.NavigateToChild(0); + List<XmlQualifiedName> l = new List<XmlQualifiedName>(); + l.Add(new XmlQualifiedName("bar")); + ctx.RegisterAttributes(l); + ctx.NavigateToAttribute(new XmlQualifiedName("bar")); + Assert.AreEqual("/foo[1]/@bar", ctx.XPath); + } + + private static IEnumerable<T> Singleton<T>(T t) { + yield return t; + } + + [Test] + public void Mixed() { + List<XPathContext.INodeInfo> l = new List<XPathContext.INodeInfo>(); + l.Add(new Text()); + l.Add(new Comment()); + l.Add(new CDATA()); + l.Add(new PI()); + l.Add(new CDATA()); + l.Add(new Comment()); + l.Add(new PI()); + l.Add(new Text()); + XPathContext ctx = new XPathContext(); + ctx.RegisterChildren(l); + ctx.NavigateToChild(0); + Assert.AreEqual("/text()[1]", ctx.XPath); + ctx.NavigateToParent(); + ctx.NavigateToChild(1); + Assert.AreEqual("/comment()[1]", ctx.XPath); + ctx.NavigateToParent(); + ctx.NavigateToChild(2); + Assert.AreEqual("/text()[2]", ctx.XPath); + ctx.NavigateToParent(); + ctx.NavigateToChild(3); + Assert.AreEqual("/processing-instruction()[1]", ctx.XPath); + ctx.NavigateToParent(); + ctx.NavigateToChild(4); + Assert.AreEqual("/text()[3]", ctx.XPath); + ctx.NavigateToParent(); + ctx.NavigateToChild(5); + Assert.AreEqual("/comment()[2]", ctx.XPath); + ctx.NavigateToParent(); + ctx.NavigateToChild(6); + Assert.AreEqual("/processing-instruction()[2]", ctx.XPath); + ctx.NavigateToParent(); + ctx.NavigateToChild(7); + Assert.AreEqual("/text()[4]", ctx.XPath); + } + + [Test] + public void ElementsAndNs() { + List<Element> l = new List<Element>(); + l.Add(new Element("foo", "urn:foo:foo")); + l.Add(new Element("foo")); + l.Add(new Element("foo", "urn:foo:bar")); + Dictionary<string, string> m = new Dictionary<string, string>(); + m["urn:foo:bar"] = "bar"; + XPathContext ctx = new XPathContext(m); + ctx.RegisterChildren(l); + ctx.NavigateToChild(0); + Assert.AreEqual("/foo[1]", ctx.XPath); + ctx.NavigateToParent(); + ctx.NavigateToChild(1); + Assert.AreEqual("/foo[2]", ctx.XPath); + ctx.NavigateToParent(); + ctx.NavigateToChild(2); + Assert.AreEqual("/bar:foo[1]", ctx.XPath); + } + + [Test] + public void AttributesAndNs() { + Dictionary<string, string> m = new Dictionary<string, string>(); + m["urn:foo:bar"] = "bar"; + XPathContext ctx = new XPathContext(m); + ctx.RegisterChildren(Singleton(new Element("foo", "urn:foo:bar"))); + ctx.NavigateToChild(0); + List<XmlQualifiedName> l = new List<XmlQualifiedName>(); + l.Add(new XmlQualifiedName("baz")); + l.Add(new XmlQualifiedName("baz", "urn:foo:bar")); + ctx.RegisterAttributes(l); + ctx.NavigateToAttribute(new XmlQualifiedName("baz")); + Assert.AreEqual("/bar:foo[1]/@baz", ctx.XPath); + ctx.NavigateToParent(); + ctx.NavigateToAttribute(new XmlQualifiedName("baz", "urn:foo:bar")); + Assert.AreEqual("/bar:foo[1]/@bar:baz", ctx.XPath); + ctx.NavigateToParent(); + } + + internal class Element : XPathContext.INodeInfo { + private readonly XmlQualifiedName name; + internal Element(string name) { + this.name = new XmlQualifiedName(name); + } + internal Element(string name, string ns) { + this.name = new XmlQualifiedName(name, ns); + } + public XmlQualifiedName Name { get { return name; } } + public XmlNodeType Type { get { return XmlNodeType.Element; } } + } + + internal abstract class NonElement : XPathContext.INodeInfo { + public XmlQualifiedName Name { get { return null; } } + public abstract XmlNodeType Type { get; } + } + internal class Text : NonElement { + public override XmlNodeType Type { + get { return XmlNodeType.Text; } + } + } + internal class Comment : NonElement { + public override XmlNodeType Type { + get { return XmlNodeType.Comment; } + } + } + internal class PI : NonElement { + public override XmlNodeType Type { + get { return XmlNodeType.ProcessingInstruction;} + } + } + internal class CDATA : NonElement { + public override XmlNodeType Type { + get { return XmlNodeType.CDATA; } + } + } + } +} \ No newline at end of file Property changes on: trunk/xmlunit/src/tests/net-core/diff/XPathContextTest.cs ___________________________________________________________________ Added: svn:eol-style + native This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |