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<>() {
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
104
105
106
107
108 public static <T> List<T> getByXPath(final Node node, final XPathAdapter xpath,
109 final PrefixResolver prefixResolver) throws TransformerException {
110 final List<T> list = new ArrayList<>();
111
112 PROCESS_XPATH_.set(Boolean.TRUE);
113 try {
114 final XPathContext xpathSupport = new XPathContext();
115 final int ctxtNode = xpathSupport.getDTMHandleFromNode(node);
116 final XObject result = xpath.execute(xpathSupport, ctxtNode, prefixResolver);
117
118 if (result instanceof XNodeSet) {
119 final NodeList nodelist = result.nodelist();
120 final int length = nodelist.getLength();
121 for (int i = 0; i < length; i++) {
122 list.add((T) nodelist.item(i));
123 }
124 }
125 else if (result instanceof XNumber) {
126 list.add((T) Double.valueOf(result.num()));
127 }
128 else if (result instanceof XBoolean) {
129 list.add((T) Boolean.valueOf(result.bool()));
130 }
131 else if (result instanceof XString) {
132 list.add((T) result.str());
133 }
134 else {
135 throw new RuntimeException("Unprocessed " + result.getClass().getName());
136 }
137 }
138 finally {
139 PROCESS_XPATH_.set(Boolean.FALSE);
140 }
141
142 return list;
143 }
144
145
146
147
148
149 public static boolean isProcessingXPath() {
150 return PROCESS_XPATH_.get().booleanValue();
151 }
152
153 }