📄 path.java
字号:
if (elem.denotesParent() && !last.denotesParent()) { if (last.denotesRoot()) { // the first element is the root element; // ".." would refer to the parent of root throw new MalformedPathException( "Path can not be canonicalized: unresolvable '..' element"); } queue.removeLast(); if (queue.isEmpty()) { last = PARENT_ELEMENT; } else { last = (PathElement) queue.getLast(); } } else if (!elem.denotesCurrent()) { last = elem; queue.add(last); } } if (queue.isEmpty()) { throw new MalformedPathException("Path can not be normalized: would result in an empty path."); } return new Path((PathElement[]) queue.toArray(new PathElement[queue.size()]), true); } /** * Returns the canonical path representation of this path. This typically * involves removing/resolving redundant elements such as "." and ".." from * the path. * * @return a canonical path representation of this path * @throws MalformedPathException if this path can not be canonicalized * (e.g. if it is relative) */ public Path getCanonicalPath() throws MalformedPathException { if (isCanonical()) { return this; } if (!isAbsolute()) { throw new MalformedPathException("only an absolute path can be canonicalized."); } return getNormalizedPath(); } /** * Computes the relative path from <code>this</code> absolute path to * <code>other</code>. * * @param other an absolute path * @return the relative path from <code>this</code> path to * <code>other</code> path * @throws MalformedPathException if either <code>this</code> or * <code>other</code> path is not absolute */ public Path computeRelativePath(Path other) throws MalformedPathException { if (other == null) { throw new IllegalArgumentException("null argument"); } // make sure both paths are absolute if (!isAbsolute() || !other.isAbsolute()) { throw new MalformedPathException("not an absolute path"); } // make sure we're comparing canonical paths Path p0 = getCanonicalPath(); Path p1 = other.getCanonicalPath(); if (p0.equals(p1)) { // both paths are equal, the relative path is therefore '.' PathBuilder pb = new PathBuilder(); pb.addLast(CURRENT_ELEMENT); return pb.getPath(); } // determine length of common path fragment int lengthCommon = 0; for (int i = 0; i < p0.getElements().length && i < p1.getElements().length; i++) { if (!p0.getElement(i).equals(p1.getElement(i))) { break; } lengthCommon++; } PathBuilder pb = new PathBuilder(); if (lengthCommon < p0.getElements().length) { /** * the common path fragment is an ancestor of this path; * this has to be accounted for by prepending '..' elements * to the relative path */ int tmp = p0.getElements().length - lengthCommon; while (tmp-- > 0) { pb.addFirst(PARENT_ELEMENT); } } // add remainder of other path for (int i = lengthCommon; i < p1.getElements().length; i++) { pb.addLast(p1.getElement(i)); } // we're done return pb.getPath(); } /** * Returns the ancestor path of the specified relative degree. * <p/> * An ancestor of relative degree <i>x</i> is the path that is <i>x</i> * levels up along the path. * <ul> * <li><i>degree</i> = 0 returns this path. * <li><i>degree</i> = 1 returns the parent of this path. * <li><i>degree</i> = 2 returns the grandparent of this path. * <li>And so on to <i>degree</i> = <i>n</i>, where <i>n</i> is the depth * of this path, which returns the root path. * </ul> * <p/> * Note that there migth be an unexpected result if <i>this</i> path is not * normalized, e.g. the ancestor of degree = 1 of the path "../.." would * be ".." although this is not the parent of "../..". * * @param degree the relative degree of the requested ancestor. * @return the ancestor path of the specified degree. * @throws PathNotFoundException if there is no ancestor of the specified degree * @throws IllegalArgumentException if <code>degree</code> is negative */ public Path getAncestor(int degree) throws IllegalArgumentException, PathNotFoundException { if (degree < 0) { throw new IllegalArgumentException("degree must be >= 0"); } else if (degree == 0) { return this; } int length = elements.length - degree; if (length < 1) { throw new PathNotFoundException("no such ancestor path of degree " + degree); } PathElement[] elements = new PathElement[length]; System.arraycopy(this.elements, 0, elements, 0, length); return new Path(elements, normalized); } /** * Returns the number of ancestors of this path. This is the equivalent * of <code>{@link #getDepth()} - 1</code>. * <p/> * Note that the returned value might be negative if this path is not * canonical, e.g. the depth of "../../a" is -1, its ancestor count is * therefore -2. * * @return the number of ancestors of this path * @see #getDepth() * @see #getLength() * @see #isCanonical() */ public int getAncestorCount() { return getDepth() - 1; } /** * Returns the length of this path, i.e. the number of its elements. * Note that the root element "/" counts as a separate element, e.g. * the length of "/a/b/c" is 4 whereas the length of "a/b/c" is 3. * <p/> * Also note that the special elements "." and ".." are not treated * specially, e.g. both "/a/./.." and "/a/b/c" have a length of 4 * but this value does not necessarily reflect the true hierarchy level as * returned by <code>{@link #getDepth()}</code>. * * @return the length of this path * @see #getDepth() * @see #getAncestorCount() */ public int getLength() { return elements.length; } /** * Returns the depth of this path. The depth reflects the absolute or * relative hierarchy level this path is representing, depending on whether * this path is an absolute or a relative path. The depth also takes '.' * and '..' elements into account. * <p/> * Note that the returned value might be negative if this path is not * canonical, e.g. the depth of "../../a" is -1. * * @return the depth this path * @see #getLength() * @see #getAncestorCount() */ public int getDepth() { int depth = ROOT_DEPTH; for (int i = 0; i < elements.length; i++) { if (elements[i].denotesParent()) { depth--; } else if (!elements[i].denotesCurrent()) { depth++; } } return depth; } /** * Determines if <i>this</i> path is an ancestor of the specified path, * based on their (absolute or relative) hierarchy level as returned by * <code>{@link #getDepth()}</code>. * * @return <code>true</code> if <code>other</code> is a descendant; * otherwise <code>false</code> * @throws MalformedPathException if not both paths are either absolute or * relative. * @see #getDepth() */ public boolean isAncestorOf(Path other) throws MalformedPathException { if (other == null) { throw new IllegalArgumentException("null argument"); } // make sure both paths are either absolute or relative if (isAbsolute() != other.isAbsolute()) { throw new MalformedPathException("cannot compare a relative path with an absolute path"); } // make sure we're comparing normalized paths Path p0 = getNormalizedPath(); Path p1 = other.getNormalizedPath(); if (p0.equals(p1)) { return false; } // calculate depth of paths (might be negative) if (p0.getDepth() >= p1.getDepth()) { return false; } for (int i = 0; i < p0.getElements().length; i++) { if (!p0.getElement(i).equals(p1.getElement(i))) { return false; } } return true; } /** * Determines if <i>this</i> path is a descendant of the specified path, * based on their (absolute or relative) hierarchy level as returned by * <code>{@link #getDepth()}</code>. * * @return <code>true</code> if <code>other</code> is an ancestor; * otherwise <code>false</code> * @throws MalformedPathException if not both paths are either absolute or * relative. * @see #getDepth() */ public boolean isDescendantOf(Path other) throws MalformedPathException { if (other == null) { throw new IllegalArgumentException("null argument"); } return other.isAncestorOf(this); } /** * Returns the name element (i.e. the last element) of this path. * * @return the name element of this path */ public PathElement getNameElement() { return elements[elements.length - 1]; } /** * Returns the elements of this path. * * @return the elements of this path. */ public PathElement[] getElements() { return elements; } /** * Returns the <code>i</code><sup>th</sup> element of this path. * * @param i element index. * @return the <code>i</code><sup>th</sup> element of this path. * @throws ArrayIndexOutOfBoundsException if this path does not have an * element at index <code>i</code>. */ public PathElement getElement(int i) { return elements[i]; } /** * Returns a string representation of this <code>Path</code> in the * JCR path format. * * @param resolver namespace resolver * @return JCR path * @throws NoPrefixDeclaredException if a namespace can not be resolved * @deprecated Use {@link PathFormat#format(Path, NamespaceResolver)} instead. */ public String toJCRPath(NamespaceResolver resolver) throws NoPrefixDeclaredException { return PathFormat.format(this, resolver); } //---------------------------------------------------------------< Object > /** * Returns the internal string representation of this <code>Path</code>. * <p/> * Note that the returned string is not a valid JCR path, i.e. the * namespace URI's of the individual path elements are not replaced with * their mapped prefixes. Call * <code>{@link #toJCRPath(NamespaceResolver)}</code> * for a JCR path representation. * * @return the internal string representation of this <code>Path</code>. */ public String toString() { // Path is immutable, we can store the string representation if (string == null) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < elements.length; i++) { if (i > 0) { // @todo find safe path separator char that does not conflict with chars in serialized QName sb.append('\t'); } PathElement element = elements[i]; String elem = element.toString(); sb.append(elem); } string = sb.toString(); } return string; } /** * Returns a <code>Path</code> holding the value of the specified * string. The string must be in the format returned by the * <code>Path.toString()</code> method. * * @param s a <code>String</code> containing the <code>Path</code> * representation to be parsed. * @return the <code>Path</code> represented by the argument * @throws IllegalArgumentException if the specified string can not be parsed * as a <code>Path</code>. * @see #toString() */ public static Path valueOf(String s) throws IllegalArgumentException { if ("".equals(s) || s == null) { throw new IllegalArgumentException("invalid Path literal"); } // split into path elements // @todo find safe path separator char that does not conflict with chars in serialized QName final char delim = '\t'; int lastPos = 0; int pos = s.indexOf(delim); ArrayList list = new ArrayList(); boolean isNormalized = true; boolean leadingParent = true; while (lastPos >= 0) { PathElement elem; if (pos >= 0) { elem = PathElement.fromString(s.substring(lastPos, pos)); lastPos = pos + 1; pos = s.indexOf(delim, lastPos); } else { elem = PathElement.fromString(s.substring(lastPos)); lastPos = -1; } list.add(elem); leadingParent &= elem.denotesParent(); isNormalized &= !elem.denotesCurrent() && (leadingParent || !elem.denotesParent()); } return new Path((PathElement[]) list.toArray(new PathElement[list.size()]), isNormalized); } /** * Returns a hash code value for this path. * * @return a hash code value for this path. * @see Object#hashCode() */ public int hashCode() { // Path is immutable, we can store the computed hash code value int h = hash; if (h == 0) { h = 17;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -