nsXULTemplateQueryProcessorXML.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  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. #include "nsCOMPtr.h"
  6. #include "nsAutoPtr.h"
  7. #include "nsIDOMDocument.h"
  8. #include "nsIDOMNode.h"
  9. #include "nsIDOMElement.h"
  10. #include "nsIDOMEvent.h"
  11. #include "nsIDocument.h"
  12. #include "nsIContent.h"
  13. #include "nsComponentManagerUtils.h"
  14. #include "nsGkAtoms.h"
  15. #include "nsIURI.h"
  16. #include "nsIArray.h"
  17. #include "nsIScriptContext.h"
  18. #include "nsArrayUtils.h"
  19. #include "nsPIDOMWindow.h"
  20. #include "nsXULContentUtils.h"
  21. #include "mozilla/dom/XPathEvaluator.h"
  22. #include "nsXULTemplateQueryProcessorXML.h"
  23. #include "nsXULTemplateResultXML.h"
  24. #include "nsXULSortService.h"
  25. #include "mozilla/dom/Element.h"
  26. #include "mozilla/dom/XMLHttpRequest.h"
  27. using namespace mozilla;
  28. using namespace mozilla::dom;
  29. NS_IMPL_ISUPPORTS(nsXMLQuery, nsXMLQuery)
  30. //----------------------------------------------------------------------
  31. //
  32. // nsXULTemplateResultSetXML
  33. //
  34. NS_IMPL_ISUPPORTS(nsXULTemplateResultSetXML, nsISimpleEnumerator)
  35. NS_IMETHODIMP
  36. nsXULTemplateResultSetXML::HasMoreElements(bool *aResult)
  37. {
  38. // if GetSnapshotLength failed, then the return type was not a set of
  39. // nodes, so just return false in this case.
  40. ErrorResult rv;
  41. uint32_t length = mResults->GetSnapshotLength(rv);
  42. if (NS_WARN_IF(rv.Failed())) {
  43. rv.SuppressException();
  44. *aResult = false;
  45. return NS_OK;
  46. }
  47. *aResult = mPosition < length;
  48. return NS_OK;
  49. }
  50. NS_IMETHODIMP
  51. nsXULTemplateResultSetXML::GetNext(nsISupports **aResult)
  52. {
  53. ErrorResult rv;
  54. nsINode* node = mResults->SnapshotItem(mPosition, rv);
  55. if (rv.Failed()) {
  56. return rv.StealNSResult();
  57. }
  58. nsXULTemplateResultXML* result =
  59. new nsXULTemplateResultXML(mQuery, node->AsContent(), mBindingSet);
  60. ++mPosition;
  61. *aResult = result;
  62. NS_ADDREF(result);
  63. return NS_OK;
  64. }
  65. //----------------------------------------------------------------------
  66. //
  67. // nsXULTemplateQueryProcessorXML
  68. //
  69. NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULTemplateQueryProcessorXML)
  70. NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXULTemplateQueryProcessorXML)
  71. tmp->mRuleToBindingsMap.Clear();
  72. NS_IMPL_CYCLE_COLLECTION_UNLINK(mRoot)
  73. NS_IMPL_CYCLE_COLLECTION_UNLINK(mEvaluator)
  74. NS_IMPL_CYCLE_COLLECTION_UNLINK(mTemplateBuilder)
  75. NS_IMPL_CYCLE_COLLECTION_UNLINK(mRequest)
  76. NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  77. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXULTemplateQueryProcessorXML)
  78. for (auto it = tmp->mRuleToBindingsMap.Iter(); !it.Done(); it.Next()) {
  79. NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mRuleToBindingsMap key");
  80. cb.NoteXPCOMChild(it.Key());
  81. }
  82. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRoot)
  83. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEvaluator)
  84. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTemplateBuilder)
  85. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRequest)
  86. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  87. NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXULTemplateQueryProcessorXML)
  88. NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXULTemplateQueryProcessorXML)
  89. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXULTemplateQueryProcessorXML)
  90. NS_INTERFACE_MAP_ENTRY(nsIXULTemplateQueryProcessor)
  91. NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
  92. NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXULTemplateQueryProcessor)
  93. NS_INTERFACE_MAP_END
  94. /*
  95. * Only the first datasource in aDataSource is used, which should be either an
  96. * nsIURI of an XML document, or a DOM node. If the former, GetDatasource will
  97. * load the document asynchronously and return null in aResult. Once the
  98. * document has loaded, the builder's datasource will be set to the XML
  99. * document. If the datasource is a DOM node, the node will be returned in
  100. * aResult.
  101. */
  102. NS_IMETHODIMP
  103. nsXULTemplateQueryProcessorXML::GetDatasource(nsIArray* aDataSources,
  104. nsIDOMNode* aRootNode,
  105. bool aIsTrusted,
  106. nsIXULTemplateBuilder* aBuilder,
  107. bool* aShouldDelayBuilding,
  108. nsISupports** aResult)
  109. {
  110. *aResult = nullptr;
  111. *aShouldDelayBuilding = false;
  112. nsresult rv;
  113. uint32_t length;
  114. aDataSources->GetLength(&length);
  115. if (length == 0)
  116. return NS_OK;
  117. // we get only the first item, because the query processor supports only
  118. // one document as a datasource
  119. nsCOMPtr<nsIDOMNode> node = do_QueryElementAt(aDataSources, 0);
  120. if (node) {
  121. return CallQueryInterface(node, aResult);
  122. }
  123. nsCOMPtr<nsIURI> uri = do_QueryElementAt(aDataSources, 0);
  124. if (!uri)
  125. return NS_ERROR_UNEXPECTED;
  126. nsAutoCString uriStr;
  127. rv = uri->GetSpec(uriStr);
  128. NS_ENSURE_SUCCESS(rv, rv);
  129. nsCOMPtr<nsIContent> root = do_QueryInterface(aRootNode);
  130. if (!root)
  131. return NS_ERROR_UNEXPECTED;
  132. nsCOMPtr<nsIDocument> doc = root->GetUncomposedDoc();
  133. if (!doc)
  134. return NS_ERROR_UNEXPECTED;
  135. nsIPrincipal *docPrincipal = doc->NodePrincipal();
  136. bool hasHadScriptObject = true;
  137. nsIScriptGlobalObject* scriptObject =
  138. doc->GetScriptHandlingObject(hasHadScriptObject);
  139. NS_ENSURE_STATE(scriptObject);
  140. nsCOMPtr<nsIXMLHttpRequest> req =
  141. do_CreateInstance(NS_XMLHTTPREQUEST_CONTRACTID, &rv);
  142. NS_ENSURE_SUCCESS(rv, rv);
  143. rv = req->Init(docPrincipal, scriptObject, nullptr, nullptr);
  144. NS_ENSURE_SUCCESS(rv, rv);
  145. rv = req->Open(NS_LITERAL_CSTRING("GET"), uriStr, true,
  146. EmptyString(), EmptyString());
  147. NS_ENSURE_SUCCESS(rv, rv);
  148. nsCOMPtr<EventTarget> target(do_QueryInterface(req));
  149. rv = target->AddEventListener(NS_LITERAL_STRING("load"), this, false);
  150. NS_ENSURE_SUCCESS(rv, rv);
  151. rv = target->AddEventListener(NS_LITERAL_STRING("error"), this, false);
  152. NS_ENSURE_SUCCESS(rv, rv);
  153. rv = req->Send(nullptr);
  154. NS_ENSURE_SUCCESS(rv, rv);
  155. mTemplateBuilder = aBuilder;
  156. mRequest = req;
  157. *aShouldDelayBuilding = true;
  158. return NS_OK;
  159. }
  160. NS_IMETHODIMP
  161. nsXULTemplateQueryProcessorXML::InitializeForBuilding(nsISupports* aDatasource,
  162. nsIXULTemplateBuilder* aBuilder,
  163. nsIDOMNode* aRootNode)
  164. {
  165. if (mGenerationStarted)
  166. return NS_ERROR_UNEXPECTED;
  167. // the datasource is either a document or a DOM element
  168. nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDatasource);
  169. if (doc)
  170. mRoot = doc->GetDocumentElement();
  171. else
  172. mRoot = do_QueryInterface(aDatasource);
  173. NS_ENSURE_STATE(mRoot);
  174. mEvaluator = new XPathEvaluator();
  175. return NS_OK;
  176. }
  177. NS_IMETHODIMP
  178. nsXULTemplateQueryProcessorXML::Done()
  179. {
  180. mGenerationStarted = false;
  181. mRuleToBindingsMap.Clear();
  182. return NS_OK;
  183. }
  184. NS_IMETHODIMP
  185. nsXULTemplateQueryProcessorXML::CompileQuery(nsIXULTemplateBuilder* aBuilder,
  186. nsIDOMNode* aQueryNode,
  187. nsIAtom* aRefVariable,
  188. nsIAtom* aMemberVariable,
  189. nsISupports** _retval)
  190. {
  191. *_retval = nullptr;
  192. nsCOMPtr<nsIContent> content = do_QueryInterface(aQueryNode);
  193. nsAutoString expr;
  194. content->GetAttr(kNameSpaceID_None, nsGkAtoms::expr, expr);
  195. // if an expression is not specified, then the default is to
  196. // just take all of the children
  197. if (expr.IsEmpty())
  198. expr.Assign('*');
  199. ErrorResult rv;
  200. nsAutoPtr<XPathExpression> compiledexpr;
  201. compiledexpr = CreateExpression(expr, content, rv);
  202. if (rv.Failed()) {
  203. nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BAD_XPATH);
  204. return rv.StealNSResult();
  205. }
  206. RefPtr<nsXMLQuery> query =
  207. new nsXMLQuery(this, aMemberVariable, Move(compiledexpr));
  208. for (nsIContent* condition = content->GetFirstChild();
  209. condition;
  210. condition = condition->GetNextSibling()) {
  211. if (condition->NodeInfo()->Equals(nsGkAtoms::assign,
  212. kNameSpaceID_XUL)) {
  213. nsAutoString var;
  214. condition->GetAttr(kNameSpaceID_None, nsGkAtoms::var, var);
  215. nsAutoString expr;
  216. condition->GetAttr(kNameSpaceID_None, nsGkAtoms::expr, expr);
  217. // ignore assignments without a variable or an expression
  218. if (!var.IsEmpty() && !expr.IsEmpty()) {
  219. compiledexpr = CreateExpression(expr, condition, rv);
  220. if (rv.Failed()) {
  221. nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BAD_ASSIGN_XPATH);
  222. return rv.StealNSResult();
  223. }
  224. nsCOMPtr<nsIAtom> varatom = NS_Atomize(var);
  225. query->AddBinding(varatom, Move(compiledexpr));
  226. }
  227. }
  228. }
  229. query.forget(_retval);
  230. return NS_OK;
  231. }
  232. NS_IMETHODIMP
  233. nsXULTemplateQueryProcessorXML::GenerateResults(nsISupports* aDatasource,
  234. nsIXULTemplateResult* aRef,
  235. nsISupports* aQuery,
  236. nsISimpleEnumerator** aResults)
  237. {
  238. if (!aQuery)
  239. return NS_ERROR_INVALID_ARG;
  240. mGenerationStarted = true;
  241. nsCOMPtr<nsXMLQuery> xmlquery = do_QueryInterface(aQuery);
  242. if (!xmlquery)
  243. return NS_ERROR_INVALID_ARG;
  244. nsCOMPtr<nsISupports> supports;
  245. nsCOMPtr<nsINode> context;
  246. if (aRef)
  247. aRef->GetBindingObjectFor(xmlquery->GetMemberVariable(),
  248. getter_AddRefs(supports));
  249. context = do_QueryInterface(supports);
  250. if (!context)
  251. context = mRoot;
  252. XPathExpression* expr = xmlquery->GetResultsExpression();
  253. if (!expr)
  254. return NS_ERROR_FAILURE;
  255. ErrorResult rv;
  256. RefPtr<XPathResult> exprresults =
  257. expr->Evaluate(*context, XPathResult::ORDERED_NODE_SNAPSHOT_TYPE,
  258. nullptr, rv);
  259. if (rv.Failed()) {
  260. return rv.StealNSResult();
  261. }
  262. RefPtr<nsXULTemplateResultSetXML> results =
  263. new nsXULTemplateResultSetXML(xmlquery, exprresults.forget(),
  264. xmlquery->GetBindingSet());
  265. results.forget(aResults);
  266. return NS_OK;
  267. }
  268. NS_IMETHODIMP
  269. nsXULTemplateQueryProcessorXML::AddBinding(nsIDOMNode* aRuleNode,
  270. nsIAtom* aVar,
  271. nsIAtom* aRef,
  272. const nsAString& aExpr)
  273. {
  274. if (mGenerationStarted)
  275. return NS_ERROR_FAILURE;
  276. RefPtr<nsXMLBindingSet> bindings = mRuleToBindingsMap.GetWeak(aRuleNode);
  277. if (!bindings) {
  278. bindings = new nsXMLBindingSet();
  279. mRuleToBindingsMap.Put(aRuleNode, bindings);
  280. }
  281. nsCOMPtr<nsINode> ruleNode = do_QueryInterface(aRuleNode);
  282. ErrorResult rv;
  283. nsAutoPtr<XPathExpression> compiledexpr;
  284. compiledexpr = CreateExpression(aExpr, ruleNode, rv);
  285. if (rv.Failed()) {
  286. rv.SuppressException();
  287. nsXULContentUtils::LogTemplateError(ERROR_TEMPLATE_BAD_BINDING_XPATH);
  288. return NS_OK;
  289. }
  290. // aRef isn't currently used for XML query processors
  291. bindings->AddBinding(aVar, Move(compiledexpr));
  292. return NS_OK;
  293. }
  294. NS_IMETHODIMP
  295. nsXULTemplateQueryProcessorXML::TranslateRef(nsISupports* aDatasource,
  296. const nsAString& aRefString,
  297. nsIXULTemplateResult** aRef)
  298. {
  299. *aRef = nullptr;
  300. // the datasource is either a document or a DOM element
  301. nsCOMPtr<Element> rootElement;
  302. nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDatasource);
  303. if (doc)
  304. rootElement = doc->GetRootElement();
  305. else
  306. rootElement = do_QueryInterface(aDatasource);
  307. // if no root element, just return. The document may not have loaded yet
  308. if (!rootElement)
  309. return NS_OK;
  310. RefPtr<nsXULTemplateResultXML> result = new nsXULTemplateResultXML(nullptr, rootElement, nullptr);
  311. result.forget(aRef);
  312. return NS_OK;
  313. }
  314. NS_IMETHODIMP
  315. nsXULTemplateQueryProcessorXML::CompareResults(nsIXULTemplateResult* aLeft,
  316. nsIXULTemplateResult* aRight,
  317. nsIAtom* aVar,
  318. uint32_t aSortHints,
  319. int32_t* aResult)
  320. {
  321. *aResult = 0;
  322. if (!aVar)
  323. return NS_OK;
  324. nsAutoString leftVal;
  325. if (aLeft)
  326. aLeft->GetBindingFor(aVar, leftVal);
  327. nsAutoString rightVal;
  328. if (aRight)
  329. aRight->GetBindingFor(aVar, rightVal);
  330. *aResult = XULSortServiceImpl::CompareValues(leftVal, rightVal, aSortHints);
  331. return NS_OK;
  332. }
  333. nsXMLBindingSet*
  334. nsXULTemplateQueryProcessorXML::GetOptionalBindingsForRule(nsIDOMNode* aRuleNode)
  335. {
  336. return mRuleToBindingsMap.GetWeak(aRuleNode);
  337. }
  338. XPathExpression*
  339. nsXULTemplateQueryProcessorXML::CreateExpression(const nsAString& aExpr,
  340. nsINode* aNode,
  341. ErrorResult& aRv)
  342. {
  343. return mEvaluator->CreateExpression(aExpr, aNode, aRv);
  344. }
  345. NS_IMETHODIMP
  346. nsXULTemplateQueryProcessorXML::HandleEvent(nsIDOMEvent* aEvent)
  347. {
  348. NS_PRECONDITION(aEvent, "aEvent null");
  349. nsAutoString eventType;
  350. aEvent->GetType(eventType);
  351. if (eventType.EqualsLiteral("load") && mTemplateBuilder) {
  352. NS_ASSERTION(mRequest, "request was not set");
  353. nsCOMPtr<nsIDOMDocument> doc;
  354. if (NS_SUCCEEDED(mRequest->GetResponseXML(getter_AddRefs(doc))))
  355. mTemplateBuilder->SetDatasource(doc);
  356. // to avoid leak. we don't need it after...
  357. mTemplateBuilder = nullptr;
  358. mRequest = nullptr;
  359. }
  360. else if (eventType.EqualsLiteral("error")) {
  361. mTemplateBuilder = nullptr;
  362. mRequest = nullptr;
  363. }
  364. return NS_OK;
  365. }