XPaths.java revision 9f554eb6d4d25a0a31be3ab88fb715fc3cee4027
1cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin/* 2cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin * Copyright (C) 2013 DroidDriver committers 3cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin * 4cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin * Licensed under the Apache License, Version 2.0 (the "License"); 5cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin * you may not use this file except in compliance with the License. 6cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin * You may obtain a copy of the License at 7cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin * 8cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin * http://www.apache.org/licenses/LICENSE-2.0 9cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin * 10cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin * Unless required by applicable law or agreed to in writing, software 11cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin * distributed under the License is distributed on an "AS IS" BASIS, 12cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin * See the License for the specific language governing permissions and 14cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin * limitations under the License. 15cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin */ 16cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin 177576fbbba2bf515908b45293b7156b5bfe088938Kevin Jinpackage com.google.android.droiddriver.finders; 18cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin 19cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin/** 20cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin * Convenience methods and constants for XPath. 215c0ca5383d9a90b6d5e9c246f387e6261fed6211Kevin Jin * <p> 225c0ca5383d9a90b6d5e9c246f387e6261fed6211Kevin Jin * DroidDriver implementation uses default XPath library on device, so the 235c0ca5383d9a90b6d5e9c246f387e6261fed6211Kevin Jin * support may be limited to <a href="http://www.w3.org/TR/xpath/">XPath 245c0ca5383d9a90b6d5e9c246f387e6261fed6211Kevin Jin * 1.0</a>. Newer XPath features may not be supported, for example, the 255c0ca5383d9a90b6d5e9c246f387e6261fed6211Kevin Jin * fn:matches function. 26cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin */ 27cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jinpublic class XPaths { 28cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin 29cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin private XPaths() {} 30cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin 31cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin /** 32cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin * @return The tag name used to build UiElement DOM. It is preferable to use 33cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin * this to build XPath instead of String literals. 34cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin */ 35cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin public static String tag(String className) { 36cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin return simpleClassName(className); 37cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin } 38cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin 39cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin /** 40cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin * @return The tag name used to build UiElement DOM. It is preferable to use 41cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin * this to build XPath instead of String literals. 42cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin */ 43cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin public static String tag(Class<?> clazz) { 44cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin return tag(clazz.getName()); 45cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin } 46cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin 47cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin private static String simpleClassName(String name) { 48cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin // the nth anonymous class has a class name ending in "Outer$n" 49cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin // and local inner classes have names ending in "Outer.$1Inner" 50cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin name = name.replaceAll("\\$[0-9]+", "\\$"); 51cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin 52cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin // we want the name of the inner class all by its lonesome 53cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin int start = name.lastIndexOf('$'); 54cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin 55cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin // if this isn't an inner class, just find the start of the 56cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin // top level class name. 57cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin if (start == -1) { 58cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin start = name.lastIndexOf('.'); 59cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin } 60cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin return name.substring(start + 1); 61cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin } 62cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin 63cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin /** 64cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin * @return XPath predicate (with enclosing []) for boolean attribute that is 65cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin * present 66cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin */ 67cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin public static String is(Attribute attribute) { 68cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin return "[@" + attribute.getName() + "]"; 69cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin } 70cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin 71cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin /** 72cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin * @return XPath predicate (with enclosing []) for boolean attribute that is 73cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin * NOT present 74cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin */ 75cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin public static String not(Attribute attribute) { 76cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin return "[not(@" + attribute.getName() + ")]"; 77cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin } 78cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin 79cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin /** @return XPath predicate (with enclosing []) for attribute with value */ 80cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin public static String attr(Attribute attribute, String value) { 81cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin return String.format("[@%s='%s']", attribute.getName(), value); 82cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin } 835c0ca5383d9a90b6d5e9c246f387e6261fed6211Kevin Jin 849f554eb6d4d25a0a31be3ab88fb715fc3cee4027Tony Wickham /** @return XPath predicate (with enclosing []) for attribute containing value */ 859f554eb6d4d25a0a31be3ab88fb715fc3cee4027Tony Wickham public static String containsAttr(Attribute attribute, String containedValue) { 869f554eb6d4d25a0a31be3ab88fb715fc3cee4027Tony Wickham return String.format("[contains(@%s, '%s')]", attribute.getName(), containedValue); 879f554eb6d4d25a0a31be3ab88fb715fc3cee4027Tony Wickham } 889f554eb6d4d25a0a31be3ab88fb715fc3cee4027Tony Wickham 895c0ca5383d9a90b6d5e9c246f387e6261fed6211Kevin Jin /** Shorthand for {@link #attr}{@code (Attribute.TEXT, value)} */ 905c0ca5383d9a90b6d5e9c246f387e6261fed6211Kevin Jin public static String text(String value) { 915c0ca5383d9a90b6d5e9c246f387e6261fed6211Kevin Jin return attr(Attribute.TEXT, value); 925c0ca5383d9a90b6d5e9c246f387e6261fed6211Kevin Jin } 93cd9468bc18d0e8250fc495f1ec656667eb206526Kevin Jin} 94