|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "nsXPathExpression.h" |
|
7 #include "txExpr.h" |
|
8 #include "txExprResult.h" |
|
9 #include "nsError.h" |
|
10 #include "nsIDOMCharacterData.h" |
|
11 #include "nsDOMClassInfoID.h" |
|
12 #include "nsIDOMDocument.h" |
|
13 #include "nsXPathResult.h" |
|
14 #include "txURIUtils.h" |
|
15 #include "txXPathTreeWalker.h" |
|
16 |
|
17 NS_IMPL_CYCLE_COLLECTION(nsXPathExpression, mDocument) |
|
18 |
|
19 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXPathExpression) |
|
20 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXPathExpression) |
|
21 |
|
22 DOMCI_DATA(XPathExpression, nsXPathExpression) |
|
23 |
|
24 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXPathExpression) |
|
25 NS_INTERFACE_MAP_ENTRY(nsIDOMXPathExpression) |
|
26 NS_INTERFACE_MAP_ENTRY(nsIDOMNSXPathExpression) |
|
27 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMXPathExpression) |
|
28 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(XPathExpression) |
|
29 NS_INTERFACE_MAP_END |
|
30 |
|
31 nsXPathExpression::nsXPathExpression(nsAutoPtr<Expr>& aExpression, |
|
32 txResultRecycler* aRecycler, |
|
33 nsIDOMDocument *aDocument) |
|
34 : mExpression(aExpression), |
|
35 mRecycler(aRecycler), |
|
36 mDocument(aDocument) |
|
37 { |
|
38 } |
|
39 |
|
40 NS_IMETHODIMP |
|
41 nsXPathExpression::Evaluate(nsIDOMNode *aContextNode, |
|
42 uint16_t aType, |
|
43 nsISupports *aInResult, |
|
44 nsISupports **aResult) |
|
45 { |
|
46 return EvaluateWithContext(aContextNode, 1, 1, aType, aInResult, aResult); |
|
47 } |
|
48 |
|
49 NS_IMETHODIMP |
|
50 nsXPathExpression::EvaluateWithContext(nsIDOMNode *aContextNode, |
|
51 uint32_t aContextPosition, |
|
52 uint32_t aContextSize, |
|
53 uint16_t aType, |
|
54 nsISupports *aInResult, |
|
55 nsISupports **aResult) |
|
56 { |
|
57 nsCOMPtr<nsINode> context = do_QueryInterface(aContextNode); |
|
58 NS_ENSURE_ARG(context); |
|
59 |
|
60 if (aContextPosition > aContextSize) |
|
61 return NS_ERROR_FAILURE; |
|
62 |
|
63 if (!nsContentUtils::CanCallerAccess(aContextNode)) |
|
64 return NS_ERROR_DOM_SECURITY_ERR; |
|
65 |
|
66 if (mDocument && mDocument != aContextNode) { |
|
67 nsCOMPtr<nsIDOMDocument> contextDocument; |
|
68 aContextNode->GetOwnerDocument(getter_AddRefs(contextDocument)); |
|
69 |
|
70 if (mDocument != contextDocument) { |
|
71 return NS_ERROR_DOM_WRONG_DOCUMENT_ERR; |
|
72 } |
|
73 } |
|
74 |
|
75 uint16_t nodeType = context->NodeType(); |
|
76 |
|
77 if (nodeType == nsIDOMNode::TEXT_NODE || |
|
78 nodeType == nsIDOMNode::CDATA_SECTION_NODE) { |
|
79 nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(aContextNode); |
|
80 NS_ENSURE_TRUE(textNode, NS_ERROR_FAILURE); |
|
81 |
|
82 if (textNode) { |
|
83 uint32_t textLength; |
|
84 textNode->GetLength(&textLength); |
|
85 if (textLength == 0) |
|
86 return NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
|
87 } |
|
88 |
|
89 // XXX Need to get logical XPath text node for CDATASection |
|
90 // and Text nodes. |
|
91 } |
|
92 else if (nodeType != nsIDOMNode::DOCUMENT_NODE && |
|
93 nodeType != nsIDOMNode::ELEMENT_NODE && |
|
94 nodeType != nsIDOMNode::ATTRIBUTE_NODE && |
|
95 nodeType != nsIDOMNode::COMMENT_NODE && |
|
96 nodeType != nsIDOMNode::PROCESSING_INSTRUCTION_NODE) { |
|
97 return NS_ERROR_DOM_NOT_SUPPORTED_ERR; |
|
98 } |
|
99 |
|
100 NS_ENSURE_ARG(aResult); |
|
101 *aResult = nullptr; |
|
102 |
|
103 nsAutoPtr<txXPathNode> contextNode(txXPathNativeNode::createXPathNode(aContextNode)); |
|
104 if (!contextNode) { |
|
105 return NS_ERROR_OUT_OF_MEMORY; |
|
106 } |
|
107 |
|
108 EvalContextImpl eContext(*contextNode, aContextPosition, aContextSize, |
|
109 mRecycler); |
|
110 nsRefPtr<txAExprResult> exprResult; |
|
111 nsresult rv = mExpression->evaluate(&eContext, getter_AddRefs(exprResult)); |
|
112 NS_ENSURE_SUCCESS(rv, rv); |
|
113 |
|
114 uint16_t resultType = aType; |
|
115 if (aType == nsIDOMXPathResult::ANY_TYPE) { |
|
116 short exprResultType = exprResult->getResultType(); |
|
117 switch (exprResultType) { |
|
118 case txAExprResult::NUMBER: |
|
119 resultType = nsIDOMXPathResult::NUMBER_TYPE; |
|
120 break; |
|
121 case txAExprResult::STRING: |
|
122 resultType = nsIDOMXPathResult::STRING_TYPE; |
|
123 break; |
|
124 case txAExprResult::BOOLEAN: |
|
125 resultType = nsIDOMXPathResult::BOOLEAN_TYPE; |
|
126 break; |
|
127 case txAExprResult::NODESET: |
|
128 resultType = nsIDOMXPathResult::UNORDERED_NODE_ITERATOR_TYPE; |
|
129 break; |
|
130 case txAExprResult::RESULT_TREE_FRAGMENT: |
|
131 NS_ERROR("Can't return a tree fragment!"); |
|
132 return NS_ERROR_FAILURE; |
|
133 } |
|
134 } |
|
135 |
|
136 // We need a result object and it must be our implementation. |
|
137 nsCOMPtr<nsIXPathResult> xpathResult = do_QueryInterface(aInResult); |
|
138 if (!xpathResult) { |
|
139 // Either no aInResult or not one of ours. |
|
140 xpathResult = new nsXPathResult(); |
|
141 NS_ENSURE_TRUE(xpathResult, NS_ERROR_OUT_OF_MEMORY); |
|
142 } |
|
143 rv = xpathResult->SetExprResult(exprResult, resultType, context); |
|
144 NS_ENSURE_SUCCESS(rv, rv); |
|
145 |
|
146 return CallQueryInterface(xpathResult, aResult); |
|
147 } |
|
148 |
|
149 /* |
|
150 * Implementation of the txIEvalContext private to nsXPathExpression |
|
151 * EvalContextImpl bases on only one context node and no variables |
|
152 */ |
|
153 |
|
154 nsresult |
|
155 nsXPathExpression::EvalContextImpl::getVariable(int32_t aNamespace, |
|
156 nsIAtom* aLName, |
|
157 txAExprResult*& aResult) |
|
158 { |
|
159 aResult = 0; |
|
160 return NS_ERROR_INVALID_ARG; |
|
161 } |
|
162 |
|
163 bool nsXPathExpression::EvalContextImpl::isStripSpaceAllowed(const txXPathNode& aNode) |
|
164 { |
|
165 return false; |
|
166 } |
|
167 |
|
168 void* nsXPathExpression::EvalContextImpl::getPrivateContext() |
|
169 { |
|
170 // we don't have a private context here. |
|
171 return nullptr; |
|
172 } |
|
173 |
|
174 txResultRecycler* nsXPathExpression::EvalContextImpl::recycler() |
|
175 { |
|
176 return mRecycler; |
|
177 } |
|
178 |
|
179 void nsXPathExpression::EvalContextImpl::receiveError(const nsAString& aMsg, |
|
180 nsresult aRes) |
|
181 { |
|
182 mLastError = aRes; |
|
183 // forward aMsg to console service? |
|
184 } |
|
185 |
|
186 const txXPathNode& nsXPathExpression::EvalContextImpl::getContextNode() |
|
187 { |
|
188 return mContextNode; |
|
189 } |
|
190 |
|
191 uint32_t nsXPathExpression::EvalContextImpl::size() |
|
192 { |
|
193 return mContextSize; |
|
194 } |
|
195 |
|
196 uint32_t nsXPathExpression::EvalContextImpl::position() |
|
197 { |
|
198 return mContextPosition; |
|
199 } |