You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by oh...@apache.org on 2006/01/15 19:27:21 UTC
svn commit: r369247 [1/2] - in /jakarta/commons/proper/configuration/trunk:
./ src/java/org/apache/commons/configuration/tree/xpath/
src/test/org/apache/commons/configuration/tree/xpath/
Author: oheger
Date: Sun Jan 15 10:26:46 2006
New Revision: 369247
URL: http://svn.apache.org/viewcvs?rev=369247&view=rev
Log:
Initial implementation of an XPATH expression engine with helper classes required by JXPath
Added:
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorAttribute.java (with props)
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorBase.java (with props)
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorChildren.java (with props)
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodePointer.java (with props)
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodePointerFactory.java (with props)
jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/XPathExpressionEngine.java (with props)
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationIteratorAttributes.java (with props)
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodeIteratorChildren.java (with props)
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodePointer.java (with props)
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodePointerFactory.java (with props)
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestXPathExpressionEngine.java (with props)
jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/XPathTest.java (with props)
Modified:
jakarta/commons/proper/configuration/trunk/project.xml
Modified: jakarta/commons/proper/configuration/trunk/project.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/project.xml?rev=369247&r1=369246&r2=369247&view=diff
==============================================================================
--- jakarta/commons/proper/configuration/trunk/project.xml (original)
+++ jakarta/commons/proper/configuration/trunk/project.xml Sun Jan 15 10:26:46 2006
@@ -267,6 +267,15 @@
</dependency>
<dependency>
+ <groupId>commons-jxpath</groupId>
+ <artifactId>commons-jxpath</artifactId>
+ <version>1.2</version>
+ <properties>
+ <war.bundle>true</war.bundle>
+ </properties>
+ </dependency>
+
+ <dependency>
<groupId>xerces</groupId>
<artifactId>xerces</artifactId>
<version>2.2.1</version>
@@ -418,6 +427,7 @@
<exclude>**/TestBasePropertiesConfiguration.java</exclude>
<exclude>**/NonStringTestHolder.java</exclude>
<exclude>**/TestAbstractConfiguration.java</exclude>
+ <exclude>**/XPathTest.java</exclude>
</excludes>
<resources>
<resource>
Added: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorAttribute.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorAttribute.java?rev=369247&view=auto
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorAttribute.java (added)
+++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorAttribute.java Sun Jan 15 10:26:46 2006
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * 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
+ *
+ * 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 org.apache.commons.configuration.tree.xpath;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.configuration.tree.ConfigurationNode;
+import org.apache.commons.jxpath.ri.QName;
+import org.apache.commons.jxpath.ri.model.NodePointer;
+
+/**
+ * A specialized node iterator implementation that deals with attribute nodes.
+ *
+ * @author Oliver Heger
+ * @version $Id$
+ */
+class ConfigurationNodeIteratorAttribute extends
+ ConfigurationNodeIteratorBase
+{
+ /** Constant for the wildcard node name.*/
+ private static final String WILDCARD = "*";
+
+ /**
+ * Creates a new instance of <code>ConfigurationNodeIteratorAttribute</code>.
+ * @param parent the parent node pointer
+ * @param name the name of the selected attribute
+ */
+ public ConfigurationNodeIteratorAttribute(NodePointer parent, QName name)
+ {
+ super(parent, false);
+ initSubNodeList(createSubNodeList((ConfigurationNode) parent.getNode(), name));
+ }
+
+ /**
+ * Determines which attributes are selected based on the passed in node
+ * name.
+ * @param node the current node
+ * @param name the name of the selected attribute
+ * @return a list with the selected attributes
+ */
+ protected List createSubNodeList(ConfigurationNode node, QName name)
+ {
+ if(name.getPrefix() != null)
+ {
+ // namespace prefixes are not supported
+ return Collections.EMPTY_LIST;
+ }
+
+ List result = new ArrayList();
+ if(!WILDCARD.equals(name.getName()))
+ {
+ result.addAll(node.getAttributes(name.getName()));
+ }
+ else
+ {
+ result.addAll(node.getAttributes());
+ }
+
+ return result;
+ }
+}
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorAttribute.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorAttribute.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorAttribute.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorBase.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorBase.java?rev=369247&view=auto
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorBase.java (added)
+++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorBase.java Sun Jan 15 10:26:46 2006
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * 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
+ *
+ * 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 org.apache.commons.configuration.tree.xpath;
+
+import java.util.List;
+
+import org.apache.commons.configuration.tree.ConfigurationNode;
+import org.apache.commons.jxpath.ri.model.NodeIterator;
+import org.apache.commons.jxpath.ri.model.NodePointer;
+
+/**
+ * <p>
+ * A base class for implementing iterators over configuration nodes.
+ * </p>
+ * <p>
+ * This class already provides common functionality for implementing the
+ * iteration process. Derived classes will implement specific behavior based on
+ * the concrete node type (child node or attribute node).
+ * </p>
+ *
+ * @since 1.3
+ * @author Oliver Heger
+ * @version $Id$
+ */
+abstract class ConfigurationNodeIteratorBase implements NodeIterator
+{
+ /** Stores the parent node pointer. */
+ private NodePointer parent;
+
+ /** Stores the list with the sub nodes. */
+ private List subNodes;
+
+ /** Stores the current position. */
+ private int position;
+
+ /** Stores the start offset of the iterator. */
+ private int startOffset;
+
+ /** Stores the reverse flag. */
+ private boolean reverse;
+
+ /**
+ * Creates a new instance of <code>ConfigurationNodeIteratorBase</code>
+ * and initializes it.
+ *
+ * @param parent the parent pointer
+ * @param reverse the reverse flag
+ */
+ protected ConfigurationNodeIteratorBase(NodePointer parent, boolean reverse)
+ {
+ this.parent = parent;
+ this.reverse = reverse;
+ }
+
+ /**
+ * Returns the position of the iteration.
+ *
+ * @return the position
+ */
+ public int getPosition()
+ {
+ return position;
+ }
+
+ /**
+ * Sets the position of the iteration.
+ *
+ * @param pos the new position
+ * @return a flag if this is a valid position
+ */
+ public boolean setPosition(int pos)
+ {
+ position = pos;
+ return pos >= 1 && pos <= getMaxPosition();
+ }
+
+ /**
+ * Returns the current node pointer.
+ *
+ * @return the current pointer in this iteration
+ */
+ public NodePointer getNodePointer()
+ {
+ if (getPosition() < 1 && !setPosition(1))
+ {
+ return null;
+ }
+
+ return createNodePointer((ConfigurationNode) subNodes
+ .get(positionToIndex(getPosition())));
+ }
+
+ /**
+ * Returns the parent node pointer.
+ *
+ * @return the parent node pointer
+ */
+ protected NodePointer getParent()
+ {
+ return parent;
+ }
+
+ /**
+ * Returns the start offset of the iteration.
+ *
+ * @return the start offset
+ */
+ protected int getStartOffset()
+ {
+ return startOffset;
+ }
+
+ /**
+ * Sets the start offset of the iteration. This is used when a start element
+ * was set.
+ *
+ * @param startOffset the start offset
+ */
+ protected void setStartOffset(int startOffset)
+ {
+ this.startOffset = startOffset;
+ if (reverse)
+ {
+ this.startOffset--;
+ }
+ else
+ {
+ this.startOffset++;
+ }
+ }
+
+ /**
+ * Initializes the list of sub nodes for the iteration. This method must be
+ * called during initialization phase.
+ *
+ * @param nodes the list with the sub nodes
+ */
+ protected void initSubNodeList(List nodes)
+ {
+ subNodes = nodes;
+ if (reverse)
+ {
+ setStartOffset(subNodes.size());
+ }
+ }
+
+ /**
+ * Returns the maximum position for this iterator.
+ *
+ * @return the maximum allowed position
+ */
+ protected int getMaxPosition()
+ {
+ return reverse ? getStartOffset() + 1 : subNodes.size()
+ - getStartOffset();
+ }
+
+ /**
+ * Creates the configuration node pointer for the current position. This
+ * method is called by <code>getNodePointer()</code>. Derived classes
+ * must create the correct pointer object.
+ *
+ * @param node the current configuration node
+ * @return the node pointer
+ */
+ protected NodePointer createNodePointer(ConfigurationNode node)
+ {
+ return new ConfigurationNodePointer(getParent(), node);
+ }
+
+ /**
+ * Returns the index in the data list for the given position. This method
+ * also checks the reverse flag.
+ *
+ * @param pos the position (1-based)
+ * @return the corresponding list index
+ */
+ protected int positionToIndex(int pos)
+ {
+ return (reverse ? 1 - pos : pos - 1) + getStartOffset();
+ }
+}
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorBase.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorBase.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorBase.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorChildren.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorChildren.java?rev=369247&view=auto
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorChildren.java (added)
+++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorChildren.java Sun Jan 15 10:26:46 2006
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * 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
+ *
+ * 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 org.apache.commons.configuration.tree.xpath;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.commons.configuration.tree.ConfigurationNode;
+import org.apache.commons.jxpath.ri.Compiler;
+import org.apache.commons.jxpath.ri.QName;
+import org.apache.commons.jxpath.ri.compiler.NodeNameTest;
+import org.apache.commons.jxpath.ri.compiler.NodeTest;
+import org.apache.commons.jxpath.ri.compiler.NodeTypeTest;
+import org.apache.commons.jxpath.ri.model.NodePointer;
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * A specialized iterator implementation for the child nodes of a configuration
+ * node.
+ *
+ * @since 1.3
+ * @author Oliver Heger
+ * @version $Id$
+ */
+class ConfigurationNodeIteratorChildren extends ConfigurationNodeIteratorBase
+{
+ /**
+ * Creates a new instance of <code>ConfigurationNodeIteratorChildren</code>
+ * and initializes it.
+ *
+ * @param parent the parent pointer
+ * @param nodeTest the test selecting the sub nodes
+ * @param reverse the reverse flag
+ * @param startsWith the first element of the iteration
+ */
+ public ConfigurationNodeIteratorChildren(NodePointer parent,
+ NodeTest nodeTest, boolean reverse, NodePointer startsWith)
+ {
+ super(parent, reverse);
+ ConfigurationNode root = (ConfigurationNode) parent.getNode();
+ List childNodes = createSubNodeList(root, nodeTest);
+ initSubNodeList(childNodes);
+ if (startsWith != null)
+ {
+ setStartOffset(findStartIndex(root,
+ (ConfigurationNode) startsWith.getNode()));
+ }
+ }
+
+ /**
+ * Creates the list with sub nodes. This method gets called during
+ * initialization phase. It finds out, based on the given test, which nodes
+ * must be iterated over.
+ *
+ * @param node the current node
+ * @param test the test object
+ * @return a list with the matching nodes
+ */
+ protected List createSubNodeList(ConfigurationNode node, NodeTest test)
+ {
+ List children = node.getChildren();
+
+ if (test == null)
+ {
+ return children;
+ }
+ else
+ {
+ if (test instanceof NodeNameTest)
+ {
+ NodeNameTest nameTest = (NodeNameTest) test;
+ QName name = nameTest.getNodeName();
+ if (name.getPrefix() == null)
+ {
+ if (nameTest.isWildcard())
+ {
+ return children;
+ }
+
+ List result = new ArrayList();
+ for (Iterator it = children.iterator(); it.hasNext();)
+ {
+ ConfigurationNode child = (ConfigurationNode) it.next();
+ if (StringUtils.equals(name.getName(), child.getName()))
+ {
+ result.add(child);
+ }
+ }
+ return result;
+ }
+ }
+
+ else if (test instanceof NodeTypeTest)
+ {
+ NodeTypeTest typeTest = (NodeTypeTest) test;
+ if (typeTest.getNodeType() == Compiler.NODE_TYPE_NODE
+ || typeTest.getNodeType() == Compiler.NODE_TYPE_TEXT)
+ {
+ return children;
+ }
+ }
+ }
+
+ return Collections.EMPTY_LIST;
+ }
+
+ /**
+ * Determines the start position of the iteration. Finds the index of the
+ * given start node in the children of the root node.
+ *
+ * @param node the root node
+ * @param startNode the start node
+ * @return the start node's index
+ */
+ protected int findStartIndex(ConfigurationNode node,
+ ConfigurationNode startNode)
+ {
+ for (int index = 0; index < node.getChildrenCount(); index++)
+ {
+ if (node.getChild(index) == startNode)
+ {
+ return index;
+ }
+ }
+
+ return -1;
+ }
+}
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorChildren.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorChildren.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorChildren.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodePointer.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodePointer.java?rev=369247&view=auto
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodePointer.java (added)
+++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodePointer.java Sun Jan 15 10:26:46 2006
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * 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
+ *
+ * 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 org.apache.commons.configuration.tree.xpath;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.commons.configuration.tree.ConfigurationNode;
+import org.apache.commons.jxpath.ri.Compiler;
+import org.apache.commons.jxpath.ri.QName;
+import org.apache.commons.jxpath.ri.compiler.NodeTest;
+import org.apache.commons.jxpath.ri.compiler.NodeTypeTest;
+import org.apache.commons.jxpath.ri.model.NodeIterator;
+import org.apache.commons.jxpath.ri.model.NodePointer;
+
+/**
+ * <p>
+ * A specific <code>NodePointer</code> implementation for configuration nodes.
+ * </p>
+ * <p>
+ * This is needed for queries using JXPath.
+ * </p>
+ *
+ * @since 1.3
+ * @author Oliver Heger
+ * @version $Id$
+ */
+class ConfigurationNodePointer extends NodePointer
+{
+ /** Stores the associated configuration node. */
+ private ConfigurationNode node;
+
+ /**
+ * Creates a new instance of <code>ConfigurationNodePointer</code>.
+ *
+ * @param node the node
+ * @param locale the locale
+ */
+ public ConfigurationNodePointer(ConfigurationNode node, Locale locale)
+ {
+ super(null, locale);
+ this.node = node;
+ }
+
+ /**
+ * Creates a new instance of <code>ConfigurationNodePointer</code> and
+ * initializes it with its parent pointer.
+ *
+ * @param parent the parent pointer
+ * @param node the associated node
+ */
+ public ConfigurationNodePointer(NodePointer parent, ConfigurationNode node)
+ {
+ super(parent);
+ this.node = node;
+ }
+
+ /**
+ * Returns a flag whether this node is a leaf. This is the case if there are
+ * no child nodes.
+ *
+ * @return a flag if this node is a leaf
+ */
+ public boolean isLeaf()
+ {
+ return node.getChildrenCount() < 1;
+ }
+
+ /**
+ * Returns a flag if this node is a collection. This is not the case.
+ *
+ * @return the collection flag
+ */
+ public boolean isCollection()
+ {
+ return false;
+ }
+
+ /**
+ * Returns this node's length. This is always 1.
+ *
+ * @return the node's length
+ */
+ public int getLength()
+ {
+ return 1;
+ }
+
+ /**
+ * Checks whether this node pointer refers to an attribute node. This method
+ * checks the attribute flag of the associated configuration node.
+ *
+ * @return the attribute flag
+ */
+ public boolean isAttribute()
+ {
+ return node.isAttribute();
+ }
+
+ /**
+ * Returns this node's name.
+ *
+ * @return the name
+ */
+ public QName getName()
+ {
+ return new QName(null, node.getName());
+ }
+
+ /**
+ * Returns this node's base value. This is the associated configuration
+ * node.
+ *
+ * @return the base value
+ */
+ public Object getBaseValue()
+ {
+ return node;
+ }
+
+ /**
+ * Returns the immediate node. This is the associated configuration node.
+ *
+ * @return the immediate node
+ */
+ public Object getImmediateNode()
+ {
+ return node;
+ }
+
+ /**
+ * Returns the value of this node.
+ *
+ * @return the represented node's value
+ */
+ public Object getValue()
+ {
+ return node.getValue();
+ }
+
+ /**
+ * Sets the value of this node.
+ *
+ * @param value the new value
+ */
+ public void setValue(Object value)
+ {
+ node.setValue(value);
+ }
+
+ /**
+ * Compares two child node pointers.
+ *
+ * @param pointer1 one pointer
+ * @param pointer2 another pointer
+ * @return a flag, which pointer should be sorted first
+ */
+ public int compareChildNodePointers(NodePointer pointer1,
+ NodePointer pointer2)
+ {
+ ConfigurationNode node1 = (ConfigurationNode) pointer1.getBaseValue();
+ ConfigurationNode node2 = (ConfigurationNode) pointer2.getBaseValue();
+
+ // attributes will be sorted before child nodes
+ if (node1.isAttribute() && !node2.isAttribute())
+ {
+ return -1;
+ }
+ else if (node2.isAttribute() && !node1.isAttribute())
+ {
+ return 1;
+ }
+
+ else
+ {
+ // sort based on the occurrence in the sub node list
+ List subNodes = node1.isAttribute() ? node.getAttributes() : node
+ .getChildren();
+ for (Iterator it = subNodes.iterator(); it.hasNext();)
+ {
+ ConfigurationNode child = (ConfigurationNode) it.next();
+ if (child == node1)
+ {
+ return -1;
+ }
+ else if (child == node2)
+ {
+ return 1;
+ }
+ }
+ return 0; // should not happen
+ }
+ }
+
+ /**
+ * Returns an iterator for the attributes that match the given name.
+ *
+ * @param name the attribute name
+ * @return the iterator for the attributes
+ */
+ public NodeIterator attributeIterator(QName name)
+ {
+ return new ConfigurationNodeIteratorAttribute(this, name);
+ }
+
+ /**
+ * Returns an iterator for the children of this pointer that match the given
+ * test object.
+ *
+ * @param test the test object
+ * @param reverse the reverse flag
+ * @param startWith the start value of the iteration
+ */
+ public NodeIterator childIterator(NodeTest test, boolean reverse,
+ NodePointer startWith)
+ {
+ return new ConfigurationNodeIteratorChildren(this, test, reverse,
+ startWith);
+ }
+
+ /**
+ * Tests if this node matches the given test. Configuration nodes are text
+ * nodes, too because they can contain a value.
+ *
+ * @param test the test object
+ * @return a flag if this node corresponds to the test
+ */
+ public boolean testNode(NodeTest test)
+ {
+ if (test instanceof NodeTypeTest
+ && ((NodeTypeTest) test).getNodeType() == Compiler.NODE_TYPE_TEXT)
+ {
+ return true;
+ }
+ return super.testNode(test);
+ }
+}
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodePointer.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodePointer.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodePointer.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodePointerFactory.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodePointerFactory.java?rev=369247&view=auto
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodePointerFactory.java (added)
+++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodePointerFactory.java Sun Jan 15 10:26:46 2006
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * 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
+ *
+ * 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 org.apache.commons.configuration.tree.xpath;
+
+import java.util.Locale;
+
+import org.apache.commons.configuration.tree.ConfigurationNode;
+import org.apache.commons.jxpath.ri.QName;
+import org.apache.commons.jxpath.ri.model.NodePointer;
+import org.apache.commons.jxpath.ri.model.NodePointerFactory;
+
+/**
+ * Implementation of the <code>NodePointerFactory</code> interface for
+ * configuration nodes.
+ *
+ * @since 1.3
+ * @author Oliver Heger
+ * @version $Id$
+ */
+public class ConfigurationNodePointerFactory implements NodePointerFactory
+{
+ /** Constant for the order of this factory. */
+ public static final int CONFIGURATION_NODE_POINTER_FACTORY_ORDER = 200;
+
+ /**
+ * Returns the order of this factory between other factories.
+ *
+ * @return this order's factory
+ */
+ public int getOrder()
+ {
+ return CONFIGURATION_NODE_POINTER_FACTORY_ORDER;
+ }
+
+ /**
+ * Creates a node pointer for the specified bean. If the bean is a
+ * configuration node, a corresponding pointer is returned.
+ *
+ * @param name the name of the node
+ * @param bean the bean
+ * @param locale the locale
+ * @return a pointer for a configuration node if the bean is such a node
+ */
+ public NodePointer createNodePointer(QName name, Object bean, Locale locale)
+ {
+ if (bean instanceof ConfigurationNode)
+ {
+ return new ConfigurationNodePointer((ConfigurationNode) bean,
+ locale);
+ }
+ return null;
+ }
+
+ /**
+ * Creates a node pointer for the specified bean. If the bean is a
+ * configuration node, a corresponding pointer is returned.
+ *
+ * @param parent the parent node
+ * @param name the name
+ * @param bean the bean
+ * @return a pointer for a configuration node if the bean is such a node
+ */
+ public NodePointer createNodePointer(NodePointer parent, QName name,
+ Object bean)
+ {
+ if (bean instanceof ConfigurationNode)
+ {
+ return new ConfigurationNodePointer(parent,
+ (ConfigurationNode) bean);
+ }
+ return null;
+ }
+}
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodePointerFactory.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodePointerFactory.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodePointerFactory.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/XPathExpressionEngine.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/XPathExpressionEngine.java?rev=369247&view=auto
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/XPathExpressionEngine.java (added)
+++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/XPathExpressionEngine.java Sun Jan 15 10:26:46 2006
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * 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
+ *
+ * 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 org.apache.commons.configuration.tree.xpath;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.apache.commons.configuration.tree.ConfigurationNode;
+import org.apache.commons.configuration.tree.ExpressionEngine;
+import org.apache.commons.configuration.tree.NodeAddData;
+import org.apache.commons.jxpath.JXPathContext;
+import org.apache.commons.jxpath.ri.JXPathContextReferenceImpl;
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * <p>
+ * A specialized implementation of the <code>ExpressionEngine</code> interface
+ * that is able to evaluate XPATH expressions.
+ * </p>
+ * <p>
+ * This class makes use of <a href="http://jakarta.apache.org/commons/jxpath/">
+ * Commons JXPath</a> for handling XPath expressions and mapping them to the
+ * nodes of a hierarchical configuration. This makes the rich and powerfull
+ * XPATH syntax available for accessing properties from a configuration object.
+ * </p>
+ * <p>
+ * For selecting properties arbitrary XPATH expressions can be used, which
+ * select single or multiple configuration nodes. The associated
+ * <code>Configuration</code> instance will directly pass the specified
+ * property keys into this engine. If a key is not syntactically correct, an
+ * exception will be thrown.
+ * </p>
+ * <p>
+ * For adding new properties, this expression engine uses a specific syntax: the
+ * "key" of a new property must consist of two parts that are
+ * separated by whitespace:
+ * <ol>
+ * <li>An XPATH expression selecting a single node, to which the new element(s)
+ * are to be added. This can be an arbitrary complex expression, but it must
+ * select exactly one node, otherwise an exception will be thrown.</li>
+ * <li>The name of the new element(s) to be added below this parent node. Here
+ * either a single node name or a complete path of nodes (separated by the
+ * "/" character) can be specified.</li>
+ * </ol>
+ * Some examples for valid keys that can be passed into the configuration's
+ * <code>addProperty()</code> method follow:
+ * </p>
+ * <p>
+ *
+ * <pre>
+ * "/tables/table[1] type"
+ * </pre>
+ *
+ * </p>
+ * <p>
+ * This will add a new <code>type</code> node as a child of the first
+ * <code>table</code> element.
+ * </p>
+ * <p>
+ *
+ * <pre>
+ * "/tables/table[1] @type"
+ * </pre>
+ *
+ * </p>
+ * <p>
+ * Similar to the example above, but this time a new attribute named
+ * <code>type</code> will be added to the first <code>table</code> element.
+ * </p>
+ * <p>
+ *
+ * <pre>
+ * "/tables table/fields/field/name"
+ * </pre>
+ *
+ * </p>
+ * <p>
+ * This example shows how a complex path can be added. Parent node is the
+ * <code>tables</code> element. Here a new branch consisting of the nodes
+ * <code>table</code>, <code>fields</code>, <code>field</code>, and
+ * <code>name</code> will be added.
+ * </p>
+ *
+ * @since 1.3
+ * @author Oliver Heger
+ * @version $Id$
+ */
+public class XPathExpressionEngine implements ExpressionEngine
+{
+ /** Constant for the path delimiter. */
+ static final String PATH_DELIMITER = "/";
+
+ /** Constant for the attribute delimiter. */
+ static final String ATTR_DELIMITER = "@";
+
+ /** Constant for the delimiters for splitting node paths. */
+ private static final String NODE_PATH_DELIMITERS = PATH_DELIMITER
+ + ATTR_DELIMITER;
+
+ /**
+ * Executes a query. The passed in property key is directly passed to a
+ * JXPath context.
+ *
+ * @param root the configuration root node
+ * @param key the query to be executed
+ * @return a list with the nodes that are selected by the query
+ */
+ public List query(ConfigurationNode root, String key)
+ {
+ if (StringUtils.isEmpty(key))
+ {
+ List result = new ArrayList(1);
+ result.add(root);
+ return result;
+ }
+ else
+ {
+ JXPathContext context = createContext(root, key);
+ List result = context.selectNodes(key);
+ return (result != null) ? result : Collections.EMPTY_LIST;
+ }
+ }
+
+ /**
+ * Returns a (canonic) key for the given node based on the parent's key.
+ * This implementation will create an XPATH expression that selects the
+ * given node (under the assumption that the passed in parent key is valid).
+ * As the <code>nodeKey()</code> implementation of
+ * <code>{@link org.apache.commons.configuration.tree.DefaultExpressionEngine DefaultExpressionEngine}</code>
+ * this method will not return indices for nodes. So all child nodes of a
+ * given parent whith the same name will have the same key.
+ *
+ * @param node the node for which a key is to be constructed
+ * @param parentKey the key of the parent node
+ * @return the key for the given node
+ */
+ public String nodeKey(ConfigurationNode node, String parentKey)
+ {
+ if (parentKey == null)
+ {
+ // name of the root node
+ return StringUtils.EMPTY;
+ }
+ else if (node.getName() == null)
+ {
+ // paranoia check for undefined node names
+ return parentKey;
+ }
+
+ else
+ {
+ StringBuffer buf = new StringBuffer(parentKey.length()
+ + node.getName().length() + PATH_DELIMITER.length());
+ if (parentKey.length() > 0)
+ {
+ buf.append(parentKey);
+ if (!node.isAttribute())
+ {
+ buf.append(PATH_DELIMITER);
+ }
+ }
+ if (node.isAttribute())
+ {
+ buf.append(ATTR_DELIMITER);
+ }
+ buf.append(node.getName());
+ return buf.toString();
+ }
+ }
+
+ /**
+ * Prepares an add operation for a configuration property. The expected
+ * format of the passed in key is explained in the class comment.
+ *
+ * @param root the configuration's root node
+ * @param key the key describing the target of the add operation and the
+ * path of the new node
+ * @return a data object to be evaluated by the calling configuration object
+ */
+ public NodeAddData prepareAdd(ConfigurationNode root, String key)
+ {
+ if (key == null)
+ {
+ throw new IllegalArgumentException(
+ "prepareAdd: key must not be null!");
+ }
+
+ int index = key.length() - 1;
+ while (index >= 0 && !Character.isWhitespace(key.charAt(index)))
+ {
+ index--;
+ }
+ if (index < 0)
+ {
+ throw new IllegalArgumentException(
+ "prepareAdd: Passed in key must contain a whitespace!");
+ }
+
+ List nodes = query(root, key.substring(0, index).trim());
+ if (nodes.size() != 1)
+ {
+ throw new IllegalArgumentException(
+ "prepareAdd: key must select exactly one target node!");
+ }
+
+ NodeAddData data = new NodeAddData();
+ data.setParent((ConfigurationNode) nodes.get(0));
+ initNodeAddData(data, key.substring(index).trim());
+ return data;
+ }
+
+ /**
+ * Creates the <code>JXPathContext</code> used for executing a query. This
+ * method will create a new context and ensure that it is correctly
+ * initialized.
+ *
+ * @param root the configuration root node
+ * @param key the key to be queried
+ * @return the new context
+ */
+ protected JXPathContext createContext(ConfigurationNode root, String key)
+ {
+ JXPathContext context = JXPathContext.newContext(root);
+ context.setLenient(true);
+ return context;
+ }
+
+ /**
+ * Initializes most properties of a <code>NodeAddData</code> object. This
+ * method is called by <code>prepareAdd()</code> after the parent node has
+ * been found. Its task is to interprete the passed in path of the new node.
+ *
+ * @param data the data object to initialize
+ * @param path the path of the new node
+ */
+ protected void initNodeAddData(NodeAddData data, String path)
+ {
+ String lastComponent = null;
+ boolean attr = false, first = true;
+
+ StringTokenizer tok = new StringTokenizer(path, NODE_PATH_DELIMITERS,
+ true);
+ while (tok.hasMoreTokens())
+ {
+ String token = tok.nextToken();
+ if (PATH_DELIMITER.equals(token))
+ {
+ if (attr)
+ {
+ invalidPath(path, " contains an attribute"
+ + " delimiter at an unallowed position.");
+ }
+ if (lastComponent == null)
+ {
+ invalidPath(path,
+ " contains a '/' at an unallowed position.");
+ }
+ data.addPathNode(lastComponent);
+ lastComponent = null;
+ }
+
+ else if (ATTR_DELIMITER.equals(token))
+ {
+ if (attr)
+ {
+ invalidPath(path,
+ " contains multiple attribute delimiters.");
+ }
+ if (lastComponent == null && !first)
+ {
+ invalidPath(path,
+ " contains an attribute delimiter at an unallowed position.");
+ }
+ if (lastComponent != null)
+ {
+ data.addPathNode(lastComponent);
+ }
+ attr = true;
+ lastComponent = null;
+ }
+
+ else
+ {
+ lastComponent = token;
+ }
+ first = false;
+ }
+
+ if (lastComponent == null)
+ {
+ invalidPath(path, "contains no components.");
+ }
+ data.setNewNodeName(lastComponent);
+ data.setAttribute(attr);
+ }
+
+ /**
+ * Helper method for throwing an exception about an invalid path.
+ *
+ * @param path the invalid path
+ * @param msg the exception message
+ */
+ private void invalidPath(String path, String msg)
+ {
+ throw new IllegalArgumentException("Invalid node path: \"" + path
+ + "\" " + msg);
+ }
+
+ // static initializer: registers the configuration node pointer factory
+ static
+ {
+ JXPathContextReferenceImpl
+ .addNodePointerFactory(new ConfigurationNodePointerFactory());
+ }
+}
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/XPathExpressionEngine.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/XPathExpressionEngine.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/tree/xpath/XPathExpressionEngine.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationIteratorAttributes.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationIteratorAttributes.java?rev=369247&view=auto
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationIteratorAttributes.java (added)
+++ jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationIteratorAttributes.java Sun Jan 15 10:26:46 2006
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * 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
+ *
+ * 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 org.apache.commons.configuration.tree.xpath;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.commons.configuration.tree.ConfigurationNode;
+import org.apache.commons.configuration.tree.DefaultConfigurationNode;
+import org.apache.commons.jxpath.ri.QName;
+import org.apache.commons.jxpath.ri.model.NodePointer;
+
+/**
+ * Test class for ConfigurationIteratorAttributes.
+ *
+ * @author Oliver Heger
+ * @version $Id$
+ */
+public class TestConfigurationIteratorAttributes extends XPathTest
+{
+ /** Constant for the name of another test attribute.*/
+ private static final String TEST_ATTR = "test";
+
+ /** Stores the node pointer of the test node.*/
+ NodePointer pointer;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+
+ // Adds further attributes to the test node
+ ConfigurationNode testNode = root.getChild(1);
+ testNode.addAttribute(new DefaultConfigurationNode(TEST_ATTR, "yes"));
+ pointer = new ConfigurationNodePointer(testNode, Locale.getDefault());
+ }
+
+ /**
+ * Tests to iterate over all attributes.
+ */
+ public void testIterateAllAttributes()
+ {
+ ConfigurationNodeIteratorAttribute it = new ConfigurationNodeIteratorAttribute(pointer, new QName(null, "*"));
+ assertEquals("Wrong number of attributes", 2, iteratorSize(it));
+ List attrs = iterationElements(it);
+ assertEquals("Wrong first attribute", ATTR_NAME, ((ConfigurationNode) attrs.get(0)).getName());
+ assertEquals("Wrong first attribute", TEST_ATTR, ((ConfigurationNode) attrs.get(1)).getName());
+ }
+
+ /**
+ * Tests to iterate over attributes with a specific name.
+ */
+ public void testIterateSpecificAttribute()
+ {
+ ConfigurationNodeIteratorAttribute it = new ConfigurationNodeIteratorAttribute(pointer, new QName(null, TEST_ATTR));
+ assertEquals("Wrong number of attributes", 1, iteratorSize(it));
+ assertEquals("Wrong attribute", TEST_ATTR, ((ConfigurationNode) iterationElements(it).get(0)).getName());
+ }
+
+ /**
+ * Tests to iterate over non existing attributes.
+ */
+ public void testIterateUnknownAttribute()
+ {
+ ConfigurationNodeIteratorAttribute it = new ConfigurationNodeIteratorAttribute(pointer, new QName(null, "unknown"));
+ assertEquals("Found attributes", 0, iteratorSize(it));
+ }
+
+ /**
+ * Tests iteration when a namespace is specified. This is not supported, so
+ * the iteration should be empty.
+ */
+ public void testIterateNamespace()
+ {
+ ConfigurationNodeIteratorAttribute it = new ConfigurationNodeIteratorAttribute(pointer, new QName("test", "*"));
+ assertEquals("Found attributes", 0, iteratorSize(it));
+ }
+}
Propchange: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationIteratorAttributes.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationIteratorAttributes.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationIteratorAttributes.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodeIteratorChildren.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodeIteratorChildren.java?rev=369247&view=auto
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodeIteratorChildren.java (added)
+++ jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodeIteratorChildren.java Sun Jan 15 10:26:46 2006
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * 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
+ *
+ * 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 org.apache.commons.configuration.tree.xpath;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.commons.configuration.tree.ConfigurationNode;
+import org.apache.commons.configuration.tree.DefaultConfigurationNode;
+import org.apache.commons.jxpath.ri.Compiler;
+import org.apache.commons.jxpath.ri.QName;
+import org.apache.commons.jxpath.ri.compiler.NodeNameTest;
+import org.apache.commons.jxpath.ri.compiler.NodeTest;
+import org.apache.commons.jxpath.ri.compiler.NodeTypeTest;
+import org.apache.commons.jxpath.ri.compiler.ProcessingInstructionTest;
+import org.apache.commons.jxpath.ri.model.NodeIterator;
+import org.apache.commons.jxpath.ri.model.NodePointer;
+
+/**
+ * Test class for ConfigurationNodeIteratorChildren.
+ *
+ * @author Oliver Heger
+ * @version $Id$
+ */
+public class TestConfigurationNodeIteratorChildren extends XPathTest
+{
+ /** Stores the node pointer to the root node. */
+ NodePointer rootPointer;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ rootPointer = new ConfigurationNodePointer(root, Locale.getDefault());
+ }
+
+ /**
+ * Tests to iterate over all children of the root node.
+ */
+ public void testIterateAllChildren()
+ {
+ ConfigurationNodeIteratorChildren it = new ConfigurationNodeIteratorChildren(
+ rootPointer, null, false, null);
+ assertEquals("Wrong number of elements", CHILD_COUNT, iteratorSize(it));
+ checkValues(it, new int[]
+ { 1, 2, 3, 4, 5 });
+ }
+
+ /**
+ * Tests a reverse iteration.
+ */
+ public void testIterateReverse()
+ {
+ ConfigurationNodeIteratorChildren it = new ConfigurationNodeIteratorChildren(
+ rootPointer, null, true, null);
+ assertEquals("Wrong number of elements", CHILD_COUNT, iteratorSize(it));
+ checkValues(it, new int[]
+ { 5, 4, 3, 2, 1 });
+ }
+
+ /**
+ * Tests using a node test with a wildcard name.
+ */
+ public void testIterateWithWildcardTest()
+ {
+ NodeNameTest test = new NodeNameTest(new QName(null, "*"));
+ ConfigurationNodeIteratorChildren it = new ConfigurationNodeIteratorChildren(
+ rootPointer, test, false, null);
+ assertEquals("Wrong number of elements", CHILD_COUNT, iteratorSize(it));
+ }
+
+ /**
+ * Tests using a node test that defines a namespace prefix. Because
+ * namespaces are not supported, no elements should be in the iteration.
+ */
+ public void testIterateWithPrefixTest()
+ {
+ NodeNameTest test = new NodeNameTest(new QName("prefix", "*"));
+ ConfigurationNodeIteratorChildren it = new ConfigurationNodeIteratorChildren(
+ rootPointer, test, false, null);
+ assertNull("Undefined node pointer not returned", it.getNodePointer());
+ assertEquals("Prefix was not evaluated", 0, iteratorSize(it));
+ }
+
+ /**
+ * Tests using a node test that selects a certain sub node name.
+ */
+ public void testIterateWithNameTest()
+ {
+ NodeNameTest test = new NodeNameTest(new QName(null, CHILD_NAME2));
+ ConfigurationNodeIteratorChildren it = new ConfigurationNodeIteratorChildren(
+ rootPointer, test, false, null);
+ assertTrue("No children found", iteratorSize(it) > 0);
+ for (Iterator elemIt = iterationElements(it).iterator(); elemIt
+ .hasNext();)
+ {
+ assertEquals("Wrong child element", CHILD_NAME2,
+ ((ConfigurationNode) elemIt.next()).getName());
+ }
+ }
+
+ /**
+ * Tests using a not supported test class. This should yield an empty
+ * iteration.
+ */
+ public void testIterateWithUnknownTest()
+ {
+ NodeTest test = new ProcessingInstructionTest("test");
+ ConfigurationNodeIteratorChildren it = new ConfigurationNodeIteratorChildren(
+ rootPointer, test, false, null);
+ assertEquals("Unknown test was not evaluated", 0, iteratorSize(it));
+ }
+
+ /**
+ * Tests using a type test for nodes. This should return all nodes.
+ */
+ public void testIterateWithNodeType()
+ {
+ NodeTypeTest test = new NodeTypeTest(Compiler.NODE_TYPE_NODE);
+ ConfigurationNodeIteratorChildren it = new ConfigurationNodeIteratorChildren(
+ rootPointer, test, false, null);
+ assertEquals("Node type not evaluated", CHILD_COUNT, iteratorSize(it));
+ }
+
+ /**
+ * Tests using a type test for a non supported type. This should return an
+ * empty iteration.
+ */
+ public void testIterateWithUnknownType()
+ {
+ NodeTypeTest test = new NodeTypeTest(Compiler.NODE_TYPE_COMMENT);
+ ConfigurationNodeIteratorChildren it = new ConfigurationNodeIteratorChildren(
+ rootPointer, test, false, null);
+ assertEquals("Unknown node type not evaluated", 0, iteratorSize(it));
+ }
+
+ /**
+ * Tests defining a start node for the iteration.
+ */
+ public void testIterateStartsWith()
+ {
+ NodePointer childPointer = new ConfigurationNodePointer(rootPointer,
+ root.getChild(2));
+ ConfigurationNodeIteratorChildren it = new ConfigurationNodeIteratorChildren(
+ rootPointer, null, false, childPointer);
+ assertEquals("Wrong start position", 0, it.getPosition());
+ List nodes = iterationElements(it);
+ assertEquals("Wrong size of iteration", CHILD_COUNT - 3, nodes.size());
+ int index = 4;
+ for (Iterator it2 = nodes.iterator(); it2.hasNext(); index++)
+ {
+ ConfigurationNode node = (ConfigurationNode) it2.next();
+ assertEquals("Wrong node value", String.valueOf(index), node
+ .getValue());
+ }
+ }
+
+ /**
+ * Tests defining a start node for a reverse iteration.
+ */
+ public void testIterateStartsWithReverse()
+ {
+ NodePointer childPointer = new ConfigurationNodePointer(rootPointer,
+ root.getChild(3));
+ ConfigurationNodeIteratorChildren it = new ConfigurationNodeIteratorChildren(
+ rootPointer, null, true, childPointer);
+ int value = 3;
+ for (int index = 1; it.setPosition(index); index++, value--)
+ {
+ ConfigurationNode node = (ConfigurationNode) it.getNodePointer()
+ .getNode();
+ assertEquals("Incorrect value at index " + index, String
+ .valueOf(value), node.getValue());
+ }
+ assertEquals("Iteration ended not at end node", 0, value);
+ }
+
+ /**
+ * Tests iteration with an invalid start node. This should cause the
+ * iteration to start at the first position.
+ */
+ public void testIterateStartsWithInvalid()
+ {
+ NodePointer childPointer = new ConfigurationNodePointer(rootPointer,
+ new DefaultConfigurationNode("newNode"));
+ ConfigurationNodeIteratorChildren it = new ConfigurationNodeIteratorChildren(
+ rootPointer, null, false, childPointer);
+ assertEquals("Wrong size of iteration", CHILD_COUNT, iteratorSize(it));
+ it.setPosition(1);
+ ConfigurationNode node = (ConfigurationNode) it.getNodePointer()
+ .getNode();
+ assertEquals("Wrong start node", "1", node.getValue());
+ }
+
+ /**
+ * Helper method for checking the values of the nodes returned by an
+ * iterator. Because the values indicate the order of the child nodes with
+ * this test it can be checked whether the nodes were returned in the
+ * correct order.
+ *
+ * @param iterator the iterator
+ * @param expectedIndices an array with the expected indices
+ */
+ private void checkValues(NodeIterator iterator, int[] expectedIndices)
+ {
+ List nodes = iterationElements(iterator);
+ for (int i = 0; i < expectedIndices.length; i++)
+ {
+ ConfigurationNode child = (ConfigurationNode) nodes.get(i);
+ assertTrue("Wrong index value for child " + i, child.getValue()
+ .toString().endsWith(String.valueOf(expectedIndices[i])));
+ }
+ }
+}
Propchange: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodeIteratorChildren.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodeIteratorChildren.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodeIteratorChildren.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodePointer.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodePointer.java?rev=369247&view=auto
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodePointer.java (added)
+++ jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodePointer.java Sun Jan 15 10:26:46 2006
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * 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
+ *
+ * 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 org.apache.commons.configuration.tree.xpath;
+
+import java.util.Locale;
+
+import org.apache.commons.configuration.tree.ConfigurationNode;
+import org.apache.commons.configuration.tree.DefaultConfigurationNode;
+import org.apache.commons.jxpath.ri.QName;
+import org.apache.commons.jxpath.ri.model.NodeIterator;
+import org.apache.commons.jxpath.ri.model.NodePointer;
+
+/**
+ * Test class for ConfigurationNodePointer.
+ *
+ * @author Oliver Heger
+ * @version $Id$
+ */
+public class TestConfigurationNodePointer extends XPathTest
+{
+ /** Stores the node pointer to be tested. */
+ NodePointer pointer;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ pointer = new ConfigurationNodePointer(root, Locale.getDefault());
+ }
+
+ /**
+ * Tests comparing child node pointers for child nodes.
+ */
+ public void testCompareChildNodePointersChildren()
+ {
+ NodePointer p1 = new ConfigurationNodePointer(pointer, root.getChild(1));
+ NodePointer p2 = new ConfigurationNodePointer(pointer, root.getChild(3));
+ assertEquals("Incorrect order", -1, pointer.compareChildNodePointers(
+ p1, p2));
+ assertEquals("Incorrect symmetric order", 1, pointer
+ .compareChildNodePointers(p2, p1));
+ }
+
+ /**
+ * Tests comparing child node pointers for attribute nodes.
+ */
+ public void testCompareChildNodePointersAttributes()
+ {
+ root.addAttribute(new DefaultConfigurationNode("attr1", "test1"));
+ root.addAttribute(new DefaultConfigurationNode("attr2", "test2"));
+ NodePointer p1 = new ConfigurationNodePointer(pointer, root
+ .getAttribute(0));
+ NodePointer p2 = new ConfigurationNodePointer(pointer, root
+ .getAttribute(1));
+ assertEquals("Incorrect order", -1, pointer.compareChildNodePointers(
+ p1, p2));
+ assertEquals("Incorrect symmetric order", 1, pointer
+ .compareChildNodePointers(p2, p1));
+ }
+
+ /**
+ * tests comparing child node pointers for both child and attribute nodes.
+ */
+ public void testCompareChildNodePointersChildAndAttribute()
+ {
+ root.addAttribute(new DefaultConfigurationNode("attr1", "test1"));
+ NodePointer p1 = new ConfigurationNodePointer(pointer, root.getChild(2));
+ NodePointer p2 = new ConfigurationNodePointer(pointer, root
+ .getAttribute(0));
+ assertEquals("Incorrect order for attributes", 1, pointer
+ .compareChildNodePointers(p1, p2));
+ assertEquals("Incorrect symmetric order for attributes", -1, pointer
+ .compareChildNodePointers(p2, p1));
+ }
+
+ /**
+ * Tests comparing child node pointers for child nodes that do not belong to
+ * the parent node.
+ */
+ public void testCompareChildNodePointersInvalidChildren()
+ {
+ ConfigurationNode node = root.getChild(1);
+ NodePointer p1 = new ConfigurationNodePointer(pointer, node.getChild(1));
+ NodePointer p2 = new ConfigurationNodePointer(pointer, node.getChild(3));
+ assertEquals("Non child nodes could be sorted", 0, pointer
+ .compareChildNodePointers(p1, p2));
+ assertEquals("Non child nodes could be sorted symmetrically", 0,
+ pointer.compareChildNodePointers(p2, p1));
+ }
+
+ /**
+ * Tests the attribute flag.
+ */
+ public void testIsAttribute()
+ {
+ ConfigurationNode node = new DefaultConfigurationNode("test", "testval");
+ NodePointer p = new ConfigurationNodePointer(pointer, node);
+ assertFalse("Node is an attribute", p.isAttribute());
+ node.setAttribute(true);
+ assertTrue("Node is no attribute", p.isAttribute());
+ }
+
+ /**
+ * Tests if leaves in the tree are correctly detected.
+ */
+ public void testIsLeave()
+ {
+ assertFalse("Root node is leaf", pointer.isLeaf());
+
+ NodePointer p = pointer;
+ while (!p.isLeaf())
+ {
+ ConfigurationNode node = (ConfigurationNode) p.getNode();
+ assertTrue("Node has no children", node.getChildrenCount() > 0);
+ p = new ConfigurationNodePointer(p, node.getChild(0));
+ }
+ assertTrue("Node has children", ((ConfigurationNode) p.getNode())
+ .getChildrenCount() == 0);
+ }
+
+ /**
+ * Tests the iterators returned by the node pointer.
+ */
+ public void testIterators()
+ {
+ checkIterators(pointer);
+ }
+
+ /**
+ * Recursive helper method for testing the returned iterators.
+ *
+ * @param p the node pointer to test
+ */
+ private void checkIterators(NodePointer p)
+ {
+ ConfigurationNode node = (ConfigurationNode) p.getNode();
+ NodeIterator it = p.childIterator(null, false, null);
+ assertEquals("Iterator count differs from children count", node
+ .getChildrenCount(), iteratorSize(it));
+
+ for (int index = 1; it.setPosition(index); index++)
+ {
+ NodePointer pchild = it.getNodePointer();
+ assertEquals("Wrong child", node.getChild(index - 1), pchild
+ .getNode());
+ checkIterators(pchild);
+ }
+
+ it = p.attributeIterator(new QName(null, "*"));
+ assertEquals("Iterator count differs from attribute count", node
+ .getAttributeCount(), iteratorSize(it));
+ for (int index = 1; it.setPosition(index); index++)
+ {
+ NodePointer pattr = it.getNodePointer();
+ assertTrue("Node pointer is no attribute", pattr.isAttribute());
+ assertEquals("Wrong attribute", node.getAttribute(index - 1), pattr
+ .getNode());
+ checkIterators(pattr);
+ }
+ }
+}
Propchange: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodePointer.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodePointer.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodePointer.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodePointerFactory.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodePointerFactory.java?rev=369247&view=auto
==============================================================================
--- jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodePointerFactory.java (added)
+++ jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodePointerFactory.java Sun Jan 15 10:26:46 2006
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * 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
+ *
+ * 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 org.apache.commons.configuration.tree.xpath;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.commons.configuration.tree.ConfigurationNode;
+import org.apache.commons.configuration.tree.DefaultConfigurationNode;
+import org.apache.commons.jxpath.JXPathContext;
+import org.apache.commons.jxpath.ri.JXPathContextReferenceImpl;
+
+/**
+ * Test class for ConfigurationNodePointerFactory. This class does not directly
+ * call the factory's methods, but rather checks if it can be installed in a
+ * <code>JXPathContext</code> and if XPath expressions can be evaluated.
+ *
+ * @author Oliver Heger
+ * @version $Id$
+ */
+public class TestConfigurationNodePointerFactory extends XPathTest
+{
+ /** Stores the JXPathContext used for testing. */
+ JXPathContext context;
+
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ JXPathContextReferenceImpl
+ .addNodePointerFactory(new ConfigurationNodePointerFactory());
+ context = JXPathContext.newContext(root);
+ context.setLenient(true);
+ }
+
+ /**
+ * Tests simple XPath expressions.
+ */
+ public void testSimpleXPath()
+ {
+ List nodes = context.selectNodes(CHILD_NAME1);
+ assertEquals("Incorrect number of results", 2, nodes.size());
+ for (Iterator it = nodes.iterator(); it.hasNext();)
+ {
+ ConfigurationNode node = (ConfigurationNode) it.next();
+ assertEquals("Incorrect node name", CHILD_NAME1, node.getName());
+ assertEquals("Incorrect parent node", root, node.getParentNode());
+ }
+
+ nodes = context.selectNodes("/" + CHILD_NAME1);
+ assertEquals("Incorrect number of results", 2, nodes.size());
+
+ nodes = context.selectNodes(CHILD_NAME2 + "/" + CHILD_NAME1 + "/"
+ + CHILD_NAME2);
+ assertEquals("Incorrect number of results", 18, nodes.size());
+ }
+
+ /**
+ * Tests using indices to specify elements.
+ */
+ public void testIndices()
+ {
+ assertEquals("Incorrect value", "1.2.3", context.getValue("/"
+ + CHILD_NAME2 + "[1]/" + CHILD_NAME1 + "[1]/" + CHILD_NAME2
+ + "[2]"));
+ assertEquals("Incorrect value of last node", String
+ .valueOf(CHILD_COUNT), context.getValue(CHILD_NAME2
+ + "[last()]"));
+
+ List nodes = context.selectNodes("/" + CHILD_NAME1 + "[1]/*");
+ assertEquals("Wrong number of children", CHILD_COUNT, nodes.size());
+ int index = 1;
+ for (Iterator it = nodes.iterator(); it.hasNext(); index++)
+ {
+ ConfigurationNode node = (ConfigurationNode) it.next();
+ assertEquals("Wrong node value for child " + index, "2." + index,
+ node.getValue());
+ }
+ }
+
+ /**
+ * Tests accessing attributes.
+ */
+ public void testAttributes()
+ {
+ root.addAttribute(new DefaultConfigurationNode("testAttr", "true"));
+ assertEquals("Did not find attribute of root node", "true", context
+ .getValue("@testAttr"));
+ assertEquals("Incorrect attribute value", "1", context.getValue("/"
+ + CHILD_NAME2 + "[1]/@" + ATTR_NAME));
+
+ assertTrue("Found elements with name attribute", context.selectNodes(
+ "//" + CHILD_NAME2 + "[@name]").isEmpty());
+ ConfigurationNode node = (ConfigurationNode) root.getChild(2).getChild(
+ 1).getChildren(CHILD_NAME2).get(1);
+ node.addAttribute(new DefaultConfigurationNode("name", "testValue"));
+ List nodes = context.selectNodes("//" + CHILD_NAME2 + "[@name]");
+ assertEquals("Name attribute not found", 1, nodes.size());
+ assertEquals("Wrong node returned", node, nodes.get(0));
+ }
+
+ /**
+ * Tests accessing a node's text.
+ */
+ public void testText()
+ {
+ List nodes = context.selectNodes("//" + CHILD_NAME2
+ + "[text()='1.1.1']");
+ assertEquals("Incorrect number of result nodes", 1, nodes.size());
+ }
+
+ /**
+ * Tests accessing the parent axis.
+ */
+ public void testParentAxis()
+ {
+ List nodes = context.selectNodes("/" + CHILD_NAME2 + "/parent::*");
+ assertEquals("Wrong number of parent nodes", 1, nodes.size());
+ }
+
+ /**
+ * Tests accessing the following sibling axis.
+ */
+ public void testFollowingSiblingAxis()
+ {
+ List nodes = context.selectNodes("/" + CHILD_NAME1
+ + "[2]/following-sibling::*");
+ assertEquals("Wrong number of following siblings", 1, nodes.size());
+ ConfigurationNode node = (ConfigurationNode) nodes.get(0);
+ assertEquals("Wrong node type", CHILD_NAME2, node.getName());
+ assertEquals("Wrong index", String.valueOf(CHILD_COUNT), node
+ .getValue());
+ }
+
+ /**
+ * Tests accessing the preceding sibling axis.
+ */
+ public void testPrecedingSiblingAxis()
+ {
+ List nodes = context.selectNodes("/" + CHILD_NAME1
+ + "[2]/preceding-sibling::*");
+ assertEquals("Wrong number of preceding siblings", 3, nodes.size());
+ for (int index = 0, value = 3; index < nodes.size(); index++, value--)
+ {
+ assertEquals("Wrong node index", String.valueOf(value),
+ ((ConfigurationNode) nodes.get(index)).getValue());
+ }
+ }
+}
Propchange: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodePointerFactory.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodePointerFactory.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Propchange: jakarta/commons/proper/configuration/trunk/src/test/org/apache/commons/configuration/tree/xpath/TestConfigurationNodePointerFactory.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org