001    /*
002     * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons-sandbox//xmlio/src/java/org/apache/commons/xmlio/in/SimplePath.java,v 1.1 2004/10/08 11:56:20 ozeigermann Exp $
003     * $Revision: 155476 $
004     * $Date: 2005-02-26 13:31:24 +0000 (Sat, 26 Feb 2005) $
005     *
006     * ====================================================================
007     *
008     * Copyright 2004 The Apache Software Foundation 
009     *
010     * Licensed under the Apache License, Version 2.0 (the "License");
011     * you may not use this file except in compliance with the License.
012     * You may obtain a copy of the License at
013     *
014     *     http://www.apache.org/licenses/LICENSE-2.0
015     *
016     * Unless required by applicable law or agreed to in writing, software
017     * distributed under the License is distributed on an "AS IS" BASIS,
018     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
019     * See the License for the specific language governing permissions and
020     * limitations under the License.
021     *
022     */
023    
024    package org.apache.commons.xmlio.in;
025    
026    import java.util.Collection;
027    import java.util.Iterator;
028    
029    /**
030     * <b>Rudimentary</b> representation of a path to an XML element. 
031     * <br>
032     * Two paths match in two cases:
033     * <ol><li>If they are really equal in terms of the {@link #equals} method.
034     * <li>If the path to match to is relative, i.e. it has no leading '/' and it is the suffix of the matching path.
035     * </ol>
036     * <br>
037     * For example<br>
038     * <code>/root/tag</code> matches <code>/root/tag</code> and<br>
039     * <code>/root/tag</code> matches <code>tag</code>.
040     *
041     */
042    public class SimplePath {
043    
044        protected final String path;
045        protected final Item[] pathList;
046    
047        /** Strips off ending slash from a string if there is one. */
048        public final static String stripEndingSlash(String path) {
049            if (path != null && path.length() > 0 && path.charAt(path.length() - 1) == '/') {
050                return path.substring(0, path.length() - 1);
051            }
052            return path;
053        }
054    
055        /** Creates a path object from a string describing it. The describing
056         * string uses '/' characters to seperate the paths parts.
057         */
058        public SimplePath(String path) {
059            this(path, null);
060        }
061    
062        /** Creates a path object from a string describing it. The describing
063         * string uses '/' characters to seperate the paths parts.
064         */
065        public SimplePath(String path, Item[] pathList) {
066            this.path = stripEndingSlash(path);
067            this.pathList = pathList;
068        }
069    
070        /** Copy ctor. */
071        public SimplePath(SimplePath path) {
072            this.path = stripEndingSlash(path.toString());
073            this.pathList = new Item[path.pathList.length];
074            System.arraycopy(path.pathList, 0, this.pathList, 0, path.pathList.length);
075        }
076    
077        /**
078         * Checks if an item matches the last segment of this path.
079         */
080        public boolean matches(Item name) {
081            return (pathList != null && pathList.length > 0 && pathList[pathList.length - 1].equals(name));
082        }
083    
084        /**
085         * Checks if the given array of items matches this path.
086         */
087        public boolean matches(Item[] path, boolean isRelative) {
088            if (pathList == null
089                || path == null
090                || path.length > pathList.length
091                || (!isRelative && path.length != pathList.length)) {
092                return false;
093            } else {
094                for (int i = path.length - 1; i >= 0; i--) {
095                    if (!pathList[i].equals(path[i])) {
096                        return false;
097                    }
098                }
099                return true;
100            }
101        }
102    
103        /**
104         * Checks if the given array of items matches this path from the root. The given path is to be considered relative.
105         * Useful to distinguish between something like /rootPath/valid/*\/valid and /rootPath/invalid/*\/valid. You will need two
106         * matches for this:
107         * <pre>
108         * matchesFromRoot(new Item[] { new Item("rootPath"), new Item("valid")}) 
109         * &&
110         * matches(new Item("valid"))
111         * </pre>
112         */
113        public boolean matchesFromRoot(Item[] path) {
114            if (pathList == null || path == null || path.length > pathList.length) {
115                return false;
116            } else {
117                for (int i = 0; i < path.length; i++) {
118                    if (!pathList[i].equals(path[i])) {
119                        return false;
120                    }
121                }
122                return true;
123            }
124        }
125    
126        /**
127         * Checks if the given array of items matches this path. The given path is to be considered relative.
128         */
129        public boolean matches(Item[] path) {
130            return matches(path, true);
131        }
132    
133        /** Finds out if the the given path matches this one. 
134         */
135        public boolean matches(SimplePath matchPath) {
136            return matches(matchPath.toString());
137        }
138    
139        /** Finds out if the path represented by the given string matches this one. 
140         * @see #matches(SimplePath)
141        */
142        public boolean matches(String matchPath) {
143            String matchString = stripEndingSlash(matchPath);
144    
145            if (matchString != null && matchString.length() > 0 && matchString.charAt(0) != '/') {
146                // relative
147                return path.endsWith("/" + matchString);
148            } else {
149                // absolute
150                return path.equals(matchString);
151            }
152        }
153    
154        /** Checks if this path matches any of the paths stored in
155         * <code>paths</code> collection. This means we iterate through 
156         * <code>paths</code> and match every entry to this path.
157         */
158        public boolean matchsAny(Collection paths) {
159            for (Iterator it = paths.iterator(); it.hasNext();) {
160                SimplePath matchPath = (SimplePath) it.next();
161                if (matches(matchPath))
162                    return true;
163            }
164            return false;
165        }
166    
167        /** Checks if this path matches any of the paths stored in
168         * <code>paths</code> collection. This means we iterate through 
169         * <code>paths</code> and match every entry to this path.
170         */
171        public boolean matchsAny(String[] paths) {
172            for (int i = 0; i < paths.length; i++) {
173                if (matches(paths[i]))
174                    return true;
175            }
176            return false;
177        }
178    
179        public String toString() {
180            return path;
181        }
182    
183        public boolean equals(Object o) {
184            if (o instanceof String) {
185                return path.equals(o);
186            } else if (o instanceof SimplePath) {
187                return path.equals(((SimplePath) o).toString());
188            } else {
189                return false;
190            }
191        }
192    
193    }