1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.html.xpath;
16
17 import java.util.ArrayList;
18 import java.util.List;
19
20 import javax.xml.transform.TransformerException;
21
22 import org.htmlunit.html.DomNode;
23 import org.htmlunit.xpath.XPathContext;
24 import org.htmlunit.xpath.objects.XBoolean;
25 import org.htmlunit.xpath.objects.XNodeSet;
26 import org.htmlunit.xpath.objects.XNumber;
27 import org.htmlunit.xpath.objects.XObject;
28 import org.htmlunit.xpath.objects.XString;
29 import org.htmlunit.xpath.xml.utils.PrefixResolver;
30 import org.w3c.dom.Document;
31 import org.w3c.dom.Node;
32 import org.w3c.dom.NodeList;
33
34
35
36
37
38
39
40
41 public final class XPathHelper {
42
43 private static final ThreadLocal<Boolean> PROCESS_XPATH_ = new ThreadLocal<Boolean>() {
44 @Override
45 protected synchronized Boolean initialValue() {
46 return Boolean.FALSE;
47 }
48 };
49
50
51
52
53 private XPathHelper() {
54
55 }
56
57
58
59
60
61
62
63
64
65
66 public static <T> List<T> getByXPath(final DomNode contextNode, final String xpathExpr,
67 final PrefixResolver prefixResolver) {
68 if (xpathExpr == null) {
69 throw new IllegalArgumentException("Null is not a valid XPath expression");
70 }
71
72 PrefixResolver resolver = prefixResolver;
73 if (resolver == null) {
74 final Node xpathExpressionContext;
75 if (contextNode.getNodeType() == Node.DOCUMENT_NODE) {
76 xpathExpressionContext = ((Document) contextNode).getDocumentElement();
77 }
78 else {
79 xpathExpressionContext = contextNode;
80 }
81
82 resolver = new HtmlUnitPrefixResolver(xpathExpressionContext);
83 }
84
85 try {
86 final boolean caseSensitive = contextNode.getPage().hasCaseSensitiveTagNames();
87 final XPathAdapter xpath = new XPathAdapter(xpathExpr, resolver, caseSensitive);
88 return getByXPath(contextNode, xpath, prefixResolver);
89 }
90 catch (final Exception e) {
91 throw new RuntimeException("Could not retrieve XPath >" + xpathExpr + "< on " + contextNode, e);
92 }
93 }
94
95
96
97
98
99
100
101
102
103 public static <T> List<T> getByXPath(final Node node, final XPathAdapter xpath,
104 final PrefixResolver prefixResolver) throws TransformerException {
105 final List<T> list = new ArrayList<>();
106
107 PROCESS_XPATH_.set(Boolean.TRUE);
108 try {
109 final XPathContext xpathSupport = new XPathContext();
110 final int ctxtNode = xpathSupport.getDTMHandleFromNode(node);
111 final XObject result = xpath.execute(xpathSupport, ctxtNode, prefixResolver);
112
113 if (result instanceof XNodeSet) {
114 final NodeList nodelist = result.nodelist();
115 final int length = nodelist.getLength();
116 for (int i = 0; i < length; i++) {
117 list.add((T) nodelist.item(i));
118 }
119 }
120 else if (result instanceof XNumber) {
121 list.add((T) Double.valueOf(result.num()));
122 }
123 else if (result instanceof XBoolean) {
124 list.add((T) Boolean.valueOf(result.bool()));
125 }
126 else if (result instanceof XString) {
127 list.add((T) result.str());
128 }
129 else {
130 throw new RuntimeException("Unproccessed " + result.getClass().getName());
131 }
132 }
133 finally {
134 PROCESS_XPATH_.set(Boolean.FALSE);
135 }
136
137 return list;
138 }
139
140
141
142
143
144 public static boolean isProcessingXPath() {
145 return PROCESS_XPATH_.get().booleanValue();
146 }
147
148 }