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