Annotation of parser3/src/classes/xnode.C, revision 1.80
1.1 parser 1: /** @file
2: Parser: @b dom parser class.
3:
1.71 paf 4: Copyright (c) 2001-2005 ArtLebedev Group (http://www.artlebedev.com)
1.38 paf 5: Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
1.1 parser 6: */
7: #include "classes.h"
8: #ifdef XML
1.46 paf 9:
1.80 ! misha 10: static const char * const IDENT_XNODE_C="$Date: 2007/08/20 10:02:51 $";
1.56 paf 11:
12: #include "pa_vmethod_frame.h"
1.1 parser 13:
1.21 paf 14: #include "pa_charset.h"
1.1 parser 15: #include "pa_request.h"
16: #include "pa_vxnode.h"
1.34 paf 17: #include "pa_vxdoc.h"
1.23 paf 18: #include "pa_vvoid.h"
1.60 paf 19: #include "pa_xml_exception.h"
1.76 misha 20: #include "pa_vbool.h"
1.1 parser 21:
22: #include "xnode.h"
1.21 paf 23: #include "libxml/xpath.h"
1.66 paf 24: #include "libxml/xpathInternals.h"
1.21 paf 25:
1.56 paf 26: // global variable
27:
28: DECLARE_CLASS_VAR(xnode, new MXnode, 0);
29:
1.21 paf 30: // classes
31:
32: class xmlXPathObject_auto_ptr {
33: public:
1.29 paf 34: explicit xmlXPathObject_auto_ptr(xmlXPathObject *_APtr = 0)
35: : _Owns(_APtr != 0), _Ptr(_APtr) {}
1.21 paf 36: xmlXPathObject_auto_ptr(const xmlXPathObject_auto_ptr& _Y)
37: : _Owns(_Y._Owns), _Ptr(_Y.release()) {}
38: xmlXPathObject_auto_ptr& operator=(const xmlXPathObject_auto_ptr& _Y)
39: {if (this != &_Y)
40: {if (_Ptr != _Y.get())
41: {if (_Owns && _Ptr)
42: xmlXPathFreeObject(_Ptr);
43: _Owns = _Y._Owns; }
44: else if (_Y._Owns)
45: _Owns = true;
46: _Ptr = _Y.release(); }
47: return (*this); }
48: ~xmlXPathObject_auto_ptr()
49: {if (_Owns && _Ptr)
50: xmlXPathFreeObject(_Ptr); }
51: xmlXPathObject& operator*() const
52: {return (*get()); }
53: xmlXPathObject *operator->() const
54: {return (get()); }
55: xmlXPathObject *get() const
56: {return (_Ptr); }
57: xmlXPathObject *release() const
58: {((xmlXPathObject_auto_ptr *)this)->_Owns = false;
59: return (_Ptr); }
60: private:
61: bool _Owns;
62: xmlXPathObject *_Ptr;
63: };
64:
65: class xmlXPathContext_auto_ptr {
66: public:
1.29 paf 67: explicit xmlXPathContext_auto_ptr(xmlXPathContext *_APtr = 0)
68: : _Owns(_APtr != 0), _Ptr(_APtr) {}
1.21 paf 69: xmlXPathContext_auto_ptr(const xmlXPathContext_auto_ptr& _Y)
70: : _Owns(_Y._Owns), _Ptr(_Y.release()) {}
71: xmlXPathContext_auto_ptr& operator=(const xmlXPathContext_auto_ptr& _Y)
72: {if (this != &_Y)
73: {if (_Ptr != _Y.get())
74: {if (_Owns && _Ptr)
75: xmlXPathFreeContext(_Ptr);
76: _Owns = _Y._Owns; }
77: else if (_Y._Owns)
78: _Owns = true;
79: _Ptr = _Y.release(); }
80: return (*this); }
81: ~xmlXPathContext_auto_ptr()
82: {if (_Owns && _Ptr)
83: xmlXPathFreeContext(_Ptr); }
84: xmlXPathContext& operator*() const
85: {return (*get()); }
86: xmlXPathContext *operator->() const
87: {return (get()); }
88: xmlXPathContext *get() const
89: {return (_Ptr); }
90: xmlXPathContext *release() const
91: {((xmlXPathContext_auto_ptr *)this)->_Owns = false;
92: return (_Ptr); }
93: private:
94: bool _Owns;
95: xmlXPathContext *_Ptr;
96: };
1.1 parser 97:
1.6 parser 98: // helpers
99:
1.72 paf 100: xmlNode& as_node(MethodParams& params, int index, const char* msg) {
1.56 paf 101: Value& value=params.as_no_junction(index, msg);
102: if(Value* vxnode=value.as(VXNODE_TYPE, false))
1.72 paf 103: return static_cast<VXnode*>(vxnode)->get_xmlnode();
104: else
1.77 misha 105: throw Exception(PARSER_RUNTIME,
1.56 paf 106: 0,
1.6 parser 107: msg);
1.72 paf 108: }
1.56 paf 109:
1.72 paf 110: xmlChar* as_xmlchar(Request& r, MethodParams& params, int index, const char* msg) {
111: return r.transcode(params.as_string(index, msg));
1.6 parser 112: }
113:
1.72 paf 114: xmlAttr& as_attr(MethodParams& params, int index, const char* msg) {
115: xmlNode& xmlnode=as_node(params, index, msg);
116: if(xmlnode.type!=XML_ATTRIBUTE_NODE)
1.77 misha 117: throw Exception(PARSER_RUNTIME,
1.56 paf 118: 0,
1.6 parser 119: msg);
120:
1.72 paf 121: return *(xmlAttr*)&xmlnode;
122: }
123:
124: static void writeNode(Request& r, VXdoc& xdoc, xmlNode* node) {
1.73 paf 125: if(!node|| xmlHaveGenericErrors())
1.72 paf 126: throw XmlException(0); // OOM, bad name, things like that
127:
128: // write out result
129: r.write_no_lang(xdoc.wrap(*node));
130: }
131:
132: static xmlNode* pa_getAttributeNodeNS(xmlNode& selfNode,
133: const xmlChar* localName,
134: const xmlChar* namespaceURI)
135: {
136: for(xmlNode* currentNode=(xmlNode*)selfNode.properties;
137: currentNode;
138: currentNode=currentNode->next)
139: {
140: if(!namespaceURI || currentNode->ns && xmlStrEqual(currentNode->ns->href, namespaceURI))
141: if(!localName || xmlStrEqual(currentNode->name, localName))
142: return currentNode;
143: }
144: return 0;
145: }
146:
147: xmlNs& pa_xmlMapNs(xmlDoc& doc, const xmlChar *href, const xmlChar *prefix) {
148: assert(href);
149: // prefix can be null
150:
151: xmlNs *cur=doc.oldNs;
152: while (cur != NULL &&
153: ((cur->prefix == NULL && prefix != NULL) ||
154: (cur->prefix != NULL && prefix == NULL) ||
155: !xmlStrEqual (cur->prefix, prefix)) &&
156: !xmlStrEqual (cur->href, href))
157: cur = cur->next;
158:
159: if (cur == NULL) {
160: cur = xmlNewNs (NULL, href, prefix);
161: if(!cur || xmlHaveGenericErrors())
162: throw XmlException(0);
163: cur->next = doc.oldNs;
164: doc.oldNs = cur;
165: }
166:
167: return *cur;
168: }
169:
170: /// todo: проверить, обновляется ли parent!
171: static void pa_addAttributeNode(xmlNode& selfNode, xmlAttr& attrNode)
172: {
173: if(attrNode.type!=XML_ATTRIBUTE_NODE)
1.77 misha 174: throw Exception(PARSER_RUNTIME,
1.72 paf 175: 0,
176: "must be ATTRIBUTE_NODE");
177:
178: /*
179: * Add it at the end to preserve parsing order ...
180: */
181: if (selfNode.properties == NULL) {
182: selfNode.properties = &attrNode;
183: } else {
184: xmlAttrPtr prev = selfNode.properties;
185:
186: while (prev->next != NULL)
187: prev = prev->next;
188: prev->next = &attrNode;
189: attrNode.prev = prev;
190: }
191:
192: if (xmlIsID(selfNode.doc, &selfNode, &attrNode) == 1)
193: xmlAddID(NULL, selfNode.doc, xmlNodeGetContent((xmlNode*)&attrNode), &attrNode);
194: }
195:
196: static const xmlChar *
197: pa_xmlGetNsURI(xmlNode *node) {
198: if (node == NULL || node->ns == NULL)
199: return NULL;
200:
201: return node->ns->href;
202: }
203:
204: #ifndef DOXYGEN
205: struct AccumulateFoundInfo
206: {
207: HashStringValue* hash;
208: VXdoc* vdoc;
209: int index;
210: };
211: #endif
212: static void AccumulateFound(xmlNode& node, AccumulateFoundInfo* info)
213: {
214: info->hash->put(
215: String::Body::Format(info->index++),
216: &info->vdoc->wrap(node));
217: }
218: template<typename I> static void
219: pa_xmlNamedPreorderTraversal (
220: xmlNode *root,
221: xmlChar *tagURI,
222: xmlChar *tagName,
223: void callback(xmlNode& node, I info),
224: I info)
225: {
226: for(xmlNode *iter=root->children; iter; iter = iter->next) {
227: if(iter->type == XML_ELEMENT_NODE &&
228: (xmlStrEqual(iter->name, tagName) ||
229: xmlStrEqual(tagName, (const xmlChar*)"*"))) {
230: if(tagURI != NULL &&
231: (xmlStrEqual(pa_xmlGetNsURI(iter), tagURI) ||
232: xmlStrEqual(tagURI, (const xmlChar*)"*")))
233: callback(*iter, info);
234: else if(tagURI == NULL)
235: callback(*iter, info);
236: }
237: pa_xmlNamedPreorderTraversal(iter, tagURI, tagName, callback, info);
238: }
239:
240: return;
1.6 parser 241: }
1.1 parser 242:
1.72 paf 243:
1.1 parser 244: // methods
245:
1.6 parser 246: // DOM1 node
247:
248: // Node insertBefore(in Node newChild,in Node refChild) raises(DOMException);
1.56 paf 249: static void _insertBefore(Request& r, MethodParams& params) {
250: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 251: VXdoc& vxdoc=vnode.get_vxdoc();
252:
253: //xmlNode& selfNode=vnode.get_xmlnode();
254: xmlNode& newChild=as_node(params, 0, "newChild must be node");
255: xmlNode& refChild=as_node(params, 1, "refChild must be node");
1.6 parser 256:
1.72 paf 257: xmlNode* retNode=xmlAddPrevSibling(&refChild, &newChild);
258: // write out result
259: writeNode(r, vxdoc, retNode);
1.6 parser 260: }
261:
262: // Node replaceChild(in Node newChild,in Node oldChild) raises(DOMException);
1.56 paf 263: static void _replaceChild(Request& r, MethodParams& params) {
264: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 265: VXdoc& vxdoc=vnode.get_vxdoc();
266: xmlDoc& xmldoc=vxdoc.get_xmldoc();
267: xmlNode& selfNode=vnode.get_xmlnode();
268: xmlNode& newChild=as_node(params, 0, "newChild must be node");
1.74 paf 269: xmlNode& oldChild=as_node(params, 1, "oldChild must be node");
1.72 paf 270:
271: if(newChild.doc!=&xmldoc)
1.74 paf 272: throw Exception("xml.dom",
1.72 paf 273: 0,
274: "WRONG_DOCUMENT_ERR");
275: if(oldChild.doc!=&xmldoc)
1.74 paf 276: throw Exception("xml.dom",
1.72 paf 277: 0,
278: "WRONG_DOCUMENT_ERR");
279:
1.74 paf 280: if(oldChild.parent!=&selfNode)
281: throw Exception("xml.dom",
282: 0,
283: "NOT_FOUND_ERR");
284:
1.72 paf 285: xmlNode* refChild=oldChild.next;
286: xmlUnlinkNode(&oldChild);
287: xmlNode* retNode;
288: if(refChild)
289: retNode=xmlAddPrevSibling(refChild, &newChild);
290: else
291: retNode=xmlAddChild(&selfNode, &newChild);
292:
293: // write out result
294: writeNode(r, vxdoc, retNode);
1.6 parser 295: }
296:
297: // Node removeChild(in Node oldChild) raises(DOMException);
1.56 paf 298: static void _removeChild(Request& r, MethodParams& params) {
299: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 300: VXdoc& vxdoc=vnode.get_vxdoc();
301: xmlDoc& xmldoc=vxdoc.get_xmldoc();
302: // xmlNode& selfNode=vnode.get_xmlnode();
303: xmlNode& oldChild=as_node(params, 0, "refChild must be node");
1.6 parser 304:
1.72 paf 305: if(oldChild.doc!=&xmldoc)
1.74 paf 306: throw Exception("xml.dom",
1.72 paf 307: 0,
308: "WRONG_DOCUMENT_ERR");
309:
310: xmlUnlinkNode(&oldChild);
311: // write out result
312: writeNode(r, vxdoc, &oldChild);
1.6 parser 313: }
314:
315: // Node appendChild(in Node newChild) raises(DOMException);
1.56 paf 316: static void _appendChild(Request& r, MethodParams& params) {
317: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 318: VXdoc& vxdoc=vnode.get_vxdoc();
319: xmlNode& selfNode=vnode.get_xmlnode();
320: xmlNode& newChild=as_node(params, 0, "newChild must be node");
1.6 parser 321:
1.72 paf 322: xmlNode* retNode=xmlAddChild(&selfNode, &newChild);
323: // write out result
324: writeNode(r, vxdoc, retNode);
1.6 parser 325: }
326:
327: // boolean hasChildNodes();
1.56 paf 328: static void _hasChildNodes(Request& r, MethodParams&) {
329: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 330: xmlNode& node=vnode.get_xmlnode();
1.6 parser 331:
332: // write out result
1.79 misha 333: r.write_no_lang(*new VBool(node.children!=0));
1.6 parser 334: }
335:
336: // Node cloneNode(in boolean deep);
1.56 paf 337: static void _cloneNode(Request& r, MethodParams& params) {
338: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 339: xmlNode& selfNode=vnode.get_xmlnode();
340: VXdoc& vxdoc=vnode.get_vxdoc();
341: xmlDoc& xmldoc=vxdoc.get_xmldoc();
1.6 parser 342:
1.56 paf 343: bool deep=params.as_bool(0, "deep must be bool", r);
1.6 parser 344:
1.72 paf 345: xmlNode* retNode=xmlDocCopyNode(&selfNode, &xmldoc, deep?1: 0);
1.6 parser 346: // write out result
1.72 paf 347: writeNode(r, vxdoc, retNode);
1.6 parser 348: }
349:
350: // DOM1 element
351:
1.72 paf 352: xmlNode& get_self_element(VXnode& vnode) {
353: xmlNode& node=vnode.get_xmlnode();
1.6 parser 354:
1.72 paf 355: if(node.type!=XML_ELEMENT_NODE)
1.77 misha 356: throw Exception(PARSER_RUNTIME,
1.56 paf 357: 0,
1.51 paf 358: "method can only be called on nodes of ELEMENT type");
1.6 parser 359:
1.72 paf 360: return node;
1.6 parser 361: }
362:
1.56 paf 363:
364: static void _getAttribute(Request& r, MethodParams& params) {
1.67 paf 365: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 366: xmlNode& element=get_self_element(vnode);
1.79 misha 367: const xmlChar* name=as_xmlchar(r, params, 0, NAME_MUST_BE_STRING);
1.6 parser 368:
1.72 paf 369: // todo: when name="xmlns"
370: xmlChar* attribute_value=xmlGetProp(&element, name);
1.6 parser 371: // write out result
1.68 paf 372: r.write_pass_lang(r.transcode(attribute_value));
1.6 parser 373: }
374:
375: // void setAttribute(in DOMString name, in DOMString value) raises(DOMException);
1.56 paf 376: static void _setAttribute(Request& r, MethodParams& params) {
1.67 paf 377: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 378: xmlNode& element=get_self_element(vnode);
1.79 misha 379: const xmlChar* name=as_xmlchar(r, params, 0, NAME_MUST_BE_STRING);
380: const xmlChar* attribute_value=as_xmlchar(r, params, 1, VALUE_MUST_BE_STRING);
1.72 paf 381:
382: // todo: when name="xmlns"
383: if(!xmlSetProp(&element, name, attribute_value))
384: throw XmlException(0);
1.6 parser 385: }
386:
387: // void removeAttribute(in DOMString name) raises(DOMException);
1.56 paf 388: static void _removeAttribute(Request& r, MethodParams& params) {
1.67 paf 389: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 390: xmlNode& element=get_self_element(vnode);
1.79 misha 391: const xmlChar* name=as_xmlchar(r, params, 0, NAME_MUST_BE_STRING);
1.6 parser 392:
1.72 paf 393: // todo: when name="xmlns"
394: xmlUnsetProp(&element, name);
1.6 parser 395: }
396:
397: // Attr getAttributeNode(in DOMString name);
1.56 paf 398: static void _getAttributeNode(Request& r, MethodParams& params) {
1.67 paf 399: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 400: VXdoc& vxdoc=vnode.get_vxdoc();
401: xmlNode& element=get_self_element(vnode);
1.79 misha 402: const xmlChar* localName=as_xmlchar(r, params, 0, NAME_MUST_BE_STRING);
1.6 parser 403:
1.72 paf 404: if(xmlNode* retNode=pa_getAttributeNodeNS(element, localName, 0)){
1.6 parser 405: // write out result
1.72 paf 406: writeNode(r, vxdoc, retNode);
407: }
1.6 parser 408: }
409:
410: // Attr setAttributeNode(in Attr newAttr) raises(DOMException);
1.72 paf 411: // Attr setAttributeNodeNS(in Attr newAttr) raises(DOMException);
1.56 paf 412: static void _setAttributeNode(Request& r, MethodParams& params) {
1.67 paf 413: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 414: VXdoc& vxdoc=vnode.get_vxdoc();
415: xmlNode& element=get_self_element(vnode);
416: xmlDoc& xmldoc=vxdoc.get_xmldoc();
417: xmlAttr& newAttr=as_attr(params, 0, "newAttr must be ATTRIBUTE node");
418:
419: if(newAttr.doc!=&xmldoc)
1.74 paf 420: throw Exception("xml.dom",
1.72 paf 421: 0,
422: "WRONG_DOCUMENT_ERR");
1.6 parser 423:
1.72 paf 424: if(newAttr.parent)
1.74 paf 425: throw Exception("xml.dom",
1.72 paf 426: 0,
427: "INUSE_ATTRIBUTE_ERR");
428:
429: if(xmlNode* retNode=pa_getAttributeNodeNS(element, newAttr.name, pa_xmlGetNsURI((xmlNode*)&newAttr))) {
1.19 paf 430: // write out result
1.72 paf 431: writeNode(r, vxdoc, retNode);
432: xmlUnlinkNode(retNode);
433: }
434:
435: pa_addAttributeNode(element, newAttr);
1.6 parser 436: }
437:
438: // Attr removeAttributeNode(in Attr oldAttr) raises(DOMException);
1.56 paf 439: static void _removeAttributeNode(Request& r, MethodParams& params) {
1.67 paf 440: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 441: VXdoc& vxdoc=vnode.get_vxdoc();
442: xmlNode& element=get_self_element(vnode);
443: xmlAttr& oldAttr=as_attr(params, 0, "oldAttr must be ATTRIBUTE node");
444:
445: if(oldAttr.parent!=&element)
1.74 paf 446: throw Exception("xml.dom",
1.72 paf 447: 0,
448: "NOT_FOUND_ERR");
1.6 parser 449:
1.72 paf 450: xmlUnlinkNode((xmlNode*)&oldAttr);
451:
452: // write out result
453: writeNode(r, vxdoc, (xmlNode*)&oldAttr);
1.6 parser 454: }
455:
456: // NodeList getElementsByTagName(in DOMString name);
1.56 paf 457: static void _getElementsByTagName(Request& r, MethodParams& params) {
1.67 paf 458: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 459: VXdoc& vxdoc=vnode.get_vxdoc();
460: xmlNode& xmlnode=vnode.get_xmlnode();
1.6 parser 461:
1.79 misha 462: xmlChar* tagName=as_xmlchar(r, params, 0, NAME_MUST_BE_STRING);
1.6 parser 463:
1.56 paf 464: VHash& result=*new VHash;
1.72 paf 465: AccumulateFoundInfo info={&result.hash(), &vxdoc, 0};
466: pa_xmlNamedPreorderTraversal(&xmlnode,
467: 0,
468: tagName,
469: AccumulateFound,
470: &info);
1.6 parser 471:
472: // write out result
473: r.write_no_lang(result);
474: }
475:
1.57 paf 476: // DOM 2
477:
1.58 paf 478: // DOMString getAttributeNS(in DOMString namespaceURI, in DOMString localName);
1.57 paf 479: static void _getAttributeNS(Request& r, MethodParams& params) {
1.67 paf 480: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 481: xmlNode& element=get_self_element(vnode);
1.57 paf 482:
1.79 misha 483: xmlChar* namespaceURI=as_xmlchar(r, params, 0, NAMESPACEURI_MUST_BE_STRING);
484: xmlChar* localName=as_xmlchar(r, params, 1, LOCALNAME_MUST_BE_STRING);
1.57 paf 485:
1.72 paf 486: // todo: when name="xmlns"
487: xmlChar* attribute_value=xmlGetNsProp(&element, localName, namespaceURI);
1.57 paf 488: // write out result
1.68 paf 489: r.write_pass_lang(r.transcode(attribute_value));
1.57 paf 490: }
491:
1.72 paf 492:
1.58 paf 493: // void setAttributeNS(in DOMString namespaceURI, in DOMString qualifiedName, in DOMString value) raises(DOMException);
1.57 paf 494: static void _setAttributeNS(Request& r, MethodParams& params) {
1.67 paf 495: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 496: xmlNode& element=get_self_element(vnode);
497: VXdoc& vxdoc=vnode.get_vxdoc();
498: xmlDoc& xmldoc=vxdoc.get_xmldoc();
1.79 misha 499: const xmlChar* namespaceURI=as_xmlchar(r, params, 0, NAMESPACEURI_MUST_BE_STRING);
1.72 paf 500: const xmlChar* qualifiedName=as_xmlchar(r, params, 1, "qualifiedName must be string");
1.79 misha 501: const xmlChar* attribute_value=as_xmlchar(r, params, 2, VALUE_MUST_BE_STRING);
1.72 paf 502:
503: xmlChar* prefix=0;
504: xmlChar* localName=xmlSplitQName2(qualifiedName, &prefix);
505:
506: // todo: name=xmlns
507: xmlAttr* attrNode;
508: if(localName) {
509: xmlNs& ns=pa_xmlMapNs(xmldoc, namespaceURI, prefix);
510:
511: attrNode=xmlSetNsProp(&element, &ns,
512: localName,
513: attribute_value);
514: } else {
515: attrNode=xmlSetProp(&element,
516: qualifiedName/*unqualified, actually*/,
517: attribute_value);
518: }
519:
520: if(!attrNode)
521: throw XmlException(0);
1.57 paf 522: }
523:
1.58 paf 524: // void removeAttributeNS(in DOMString namespaceURI, in DOMString localName) raises(DOMException);
1.57 paf 525: static void _removeAttributeNS(Request& r, MethodParams& params) {
1.67 paf 526: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 527: xmlNode& element=get_self_element(vnode);
528: VXdoc& vxdoc=vnode.get_vxdoc();
529: xmlDoc& xmldoc=vxdoc.get_xmldoc();
1.79 misha 530: const xmlChar* namespaceURI=as_xmlchar(r, params, 0, NAMESPACEURI_MUST_BE_STRING);
531: const xmlChar* localName=as_xmlchar(r, params, 1, LOCALNAME_MUST_BE_STRING);
1.72 paf 532:
533: // todo: when name="xmlns"
534: xmlNs& ns=pa_xmlMapNs(xmldoc, namespaceURI, 0);
535: xmlUnsetNsProp(&element, &ns, localName);
1.57 paf 536: }
537:
1.58 paf 538: // Attr getAttributeNodeNS(in DOMString namespaceURI, in DOMString localName);
1.57 paf 539: static void _getAttributeNodeNS(Request& r, MethodParams& params) {
1.67 paf 540: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 541: VXdoc& vxdoc=vnode.get_vxdoc();
542: xmlNode& element=get_self_element(vnode);
1.79 misha 543: const xmlChar* namespaceURI=as_xmlchar(r, params, 0, NAMESPACEURI_MUST_BE_STRING);
544: const xmlChar* localName=as_xmlchar(r, params, 1, LOCALNAME_MUST_BE_STRING);
1.57 paf 545:
1.72 paf 546: if(xmlNode* retNode=pa_getAttributeNodeNS(element, localName, namespaceURI)){
1.57 paf 547: // write out result
1.72 paf 548: writeNode(r, vxdoc, retNode);
549: }
550: }
1.57 paf 551:
1.58 paf 552: // boolean hasAttribute(in DOMString name) raises(DOMException);
1.57 paf 553: static void _hasAttribute(Request& r, MethodParams& params) {
1.67 paf 554: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 555: xmlNode& element=get_self_element(vnode);
1.57 paf 556:
1.79 misha 557: const xmlChar* name=as_xmlchar(r, params, 0, NAME_MUST_BE_STRING);
1.57 paf 558:
1.72 paf 559: // todo: when name="xmlns"
1.57 paf 560: // write out result
1.79 misha 561: r.write_no_lang(*new VBool(xmlGetProp(&element, name)!=0));
1.57 paf 562: }
563:
1.58 paf 564: // boolean hasAttributeNS(n DOMString namespaceURI, in DOMString localName) raises(DOMException);
1.57 paf 565: static void _hasAttributeNS(Request& r, MethodParams& params) {
1.67 paf 566: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 567: xmlNode& element=get_self_element(vnode);
1.57 paf 568:
1.79 misha 569: const xmlChar* namespaceURI=as_xmlchar(r, params, 0, NAMESPACEURI_MUST_BE_STRING);
570: const xmlChar* localName=as_xmlchar(r, params, 1, LOCALNAME_MUST_BE_STRING);
1.57 paf 571:
572: // write out result
1.79 misha 573: r.write_no_lang(*new VBool(xmlGetNsProp(&element, localName, namespaceURI)!=0));
1.57 paf 574: }
575:
1.78 misha 576: // boolean hasAttributes
577: static void _hasAttributes(Request& r, MethodParams&) {
578: VXnode& vnode=GET_SELF(r, VXnode);
579: xmlNode& element=get_self_element(vnode);
580:
581: // write out result
582: r.write_no_lang(*new VBool(element.properties!=0));
583: }
584:
1.56 paf 585: static void _getElementsByTagNameNS(Request& r, MethodParams& params) {
1.67 paf 586: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 587: VXdoc& vdoc=vnode.get_vxdoc();
588: xmlDoc& xmldoc=vdoc.get_xmldoc();
1.39 paf 589:
590: // namespaceURI;localName
1.79 misha 591: xmlChar* namespaceURI=as_xmlchar(r, params, 0, NAMESPACEURI_MUST_BE_STRING);
592: xmlChar* localName=as_xmlchar(r, params, 1, NAME_MUST_BE_STRING);
1.39 paf 593:
1.56 paf 594: VHash& result=*new VHash;
1.72 paf 595: AccumulateFoundInfo info={&result.hash(), &vdoc, 0};
596: pa_xmlNamedPreorderTraversal((xmlNode*)&xmldoc,
597: namespaceURI,
598: localName,
599: AccumulateFound,
600: &info);
1.39 paf 601:
602: // write out result
603: r.write_no_lang(result);
604: }
605:
1.72 paf 606:
1.6 parser 607: // void normalize();
1.72 paf 608: static void _normalize(Request&, MethodParams&) {
609: /*maybe someday
1.56 paf 610: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 611: xmlNode& selfNode=vnode.get_xmlnode();
1.6 parser 612:
1.19 paf 613: gdome_n_normalize(selfNode, &exc);
614: if(exc)
1.60 paf 615: throw XmlException(0, exc);
1.72 paf 616: */
1.6 parser 617: }
1.25 paf 618:
1.66 paf 619: #ifndef DOXYGEN
620: struct Register_one_ns_info {
621: Request* r;
622: xmlXPathContextPtr ctxt;
623: };
624: #endif
625: static void register_one_ns(
626: HashStringValue::key_type key,
627: HashStringValue::value_type value,
628: Register_one_ns_info* info) {
629: if(const String* svalue=value->get_string())
630: xmlXPathRegisterNs(info->ctxt,
1.72 paf 631: info->r->transcode(key),
632: info->r->transcode(*svalue));
1.66 paf 633: else
1.77 misha 634: throw Exception(PARSER_RUNTIME,
1.66 paf 635: new String(key, String::L_TAINTED),
636: "value is %s, must be string or number", value->type());
637: }
1.56 paf 638: static void _selectX(Request& r, MethodParams& params,
639: void (*handler)(Request& r,
1.26 paf 640: const String& expression,
641: xmlXPathObject_auto_ptr res,
1.67 paf 642: VXdoc& xdoc,
1.72 paf 643: Value*& result))
644: {
1.56 paf 645: VXnode& vnode=GET_SELF(r, VXnode);
1.74 paf 646: xmlNode& xmlnode=vnode.get_xmlnode();
1.72 paf 647: VXdoc& vdoc=vnode.get_vxdoc();
648: xmlDoc& xmldoc=vdoc.get_xmldoc();
1.1 parser 649:
650: // expression
1.56 paf 651: const String& expression=params.as_string(0, "expression must be string");
1.72 paf 652: xmlXPathContext_auto_ptr ctxt(xmlXPathNewContext(&xmldoc));
1.67 paf 653: {
1.66 paf 654: Register_one_ns_info info={&r, ctxt.get()};
1.75 paf 655: vdoc.search_namespaces.hash().for_each<Register_one_ns_info*>(register_one_ns, &info);
1.66 paf 656: }
1.74 paf 657: ctxt->node=&xmlnode;
1.25 paf 658: /*error to stderr for now*/
659: xmlXPathObject_auto_ptr res(
1.72 paf 660: xmlXPathEvalExpression(r.transcode(expression), ctxt.get()));
1.28 paf 661:
1.72 paf 662: if(xmlHaveGenericErrors())
663: throw XmlException(0);
1.25 paf 664:
1.56 paf 665: Value* result=0;
1.25 paf 666: if(res.get())
1.72 paf 667: handler(r, expression, res, vdoc, result);
1.44 paf 668: if(result)
1.26 paf 669: r.write_no_lang(*result);
670: }
1.25 paf 671:
1.72 paf 672: static void selectNodesHandler(Request&,
1.56 paf 673: const String& expression,
674: xmlXPathObject_auto_ptr res,
1.67 paf 675: VXdoc& xdoc,
1.56 paf 676: Value*& result) {
677: VHash& vhash=*new VHash; result=&vhash;
1.26 paf 678: switch(res->type) {
679: case XPATH_UNDEFINED:
680: break;
681: case XPATH_NODESET:
1.40 paf 682: if(res->nodesetval)
683: if(int size=res->nodesetval->nodeNr) {
1.56 paf 684: HashStringValue& hash=vhash.hash();
685: for(int i=0; i<size; i++)
686: hash.put(
1.59 paf 687: String::Body::Format(i),
1.72 paf 688: &xdoc.wrap(*res->nodesetval->nodeTab[i]));
1.1 parser 689: }
1.26 paf 690: break;
691: default:
1.77 misha 692: throw Exception(PARSER_RUNTIME,
1.26 paf 693: &expression,
694: "wrong xmlXPathEvalExpression result type (%d)", res->type);
695: break; // never
696: }
697: }
698:
1.56 paf 699: static void selectNodeHandler(Request& r,
700: const String& expression,
1.67 paf 701: xmlXPathObject_auto_ptr res,
702: VXdoc& xdoc,
703: Value*& result) {
1.26 paf 704: switch(res->type) {
705: case XPATH_UNDEFINED:
706: break;
707: case XPATH_NODESET:
1.80 ! misha 708: if(res->nodesetval && res->nodesetval->nodeNr) { // empty result strangely has NODESET res->type
1.26 paf 709: if(res->nodesetval->nodeNr>1)
1.77 misha 710: throw Exception(PARSER_RUNTIME,
1.56 paf 711: &expression,
712: "resulted not in a single node (%d)", res->nodesetval->nodeNr);
1.26 paf 713:
1.72 paf 714: result=&xdoc.wrap(*res->nodesetval->nodeTab[0]);
1.25 paf 715: }
1.26 paf 716: break;
717: case XPATH_BOOLEAN:
1.56 paf 718: result=new VBool(res->boolval!=0);
1.26 paf 719: break;
720: case XPATH_NUMBER:
1.56 paf 721: result=new VDouble(res->floatval);
1.26 paf 722: break;
723: case XPATH_STRING:
1.56 paf 724: result=new VString(r.transcode((xmlChar*)res->stringval));
1.26 paf 725: break;
726: default:
1.77 misha 727: throw Exception(PARSER_RUNTIME,
1.26 paf 728: &expression,
729: "wrong xmlXPathEvalExpression result type (%d)", res->type);
730: }
731: }
732:
1.62 paf 733: static void selectBoolHandler(Request&,
1.56 paf 734: const String& expression,
735: xmlXPathObject_auto_ptr res,
1.67 paf 736: VXdoc& /*xdoc*/,
1.56 paf 737: Value*& result) {
1.26 paf 738: switch(res->type) {
739: case XPATH_BOOLEAN:
1.56 paf 740: result=new VBool(res->boolval!=0);
1.26 paf 741: break;
742: case XPATH_NODESET:
1.40 paf 743: if(!(res->nodesetval && res->nodesetval->nodeNr))
1.26 paf 744: break;
745: // else[nodeset] fall down to default
746: default:
1.77 misha 747: throw Exception(PARSER_RUNTIME,
1.26 paf 748: &expression,
749: "wrong xmlXPathEvalExpression result type (%d)", res->type);
750: break; // never
751: }
752: }
1.1 parser 753:
1.62 paf 754: static void selectNumberHandler(Request&,
1.56 paf 755: const String& expression,
756: xmlXPathObject_auto_ptr res,
1.67 paf 757: VXdoc& /*xdoc*/,
1.56 paf 758: Value*& result) {
1.26 paf 759: switch(res->type) {
760: case XPATH_NUMBER:
1.56 paf 761: result=new VDouble(res->floatval);
1.26 paf 762: break;
763: case XPATH_NODESET:
1.40 paf 764: if(!(res->nodesetval && res->nodesetval->nodeNr))
1.26 paf 765: break;
766: // else[nodeset] fall down to default
767: default:
1.77 misha 768: throw Exception(PARSER_RUNTIME,
1.26 paf 769: &expression,
770: "wrong xmlXPathEvalExpression result type (%d)", res->type);
771: break; // never
772: }
773: }
774:
1.56 paf 775: static void selectStringHandler(Request& r,
1.26 paf 776: const String& expression,
777: xmlXPathObject_auto_ptr res,
1.67 paf 778: VXdoc& /*xdoc*/,
1.56 paf 779: Value*& result) {
1.26 paf 780: switch(res->type) {
781: case XPATH_UNDEFINED:
782: break;
783: case XPATH_STRING:
1.56 paf 784: result=new VString(r.transcode((xmlChar*)res->stringval));
1.26 paf 785: break;
786: case XPATH_NODESET:
1.40 paf 787: if(!(res->nodesetval && res->nodesetval->nodeNr))
1.26 paf 788: break;
789: // else[nodeset] fall down to default
790: default:
1.77 misha 791: throw Exception(PARSER_RUNTIME,
1.26 paf 792: &expression,
793: "wrong xmlXPathEvalExpression result type (%d)", res->type);
794: break; // never
1.1 parser 795: }
796: }
1.25 paf 797:
1.56 paf 798: static void _select(Request& r, MethodParams& params) {
799: _selectX(r, params,
1.26 paf 800: selectNodesHandler);
801: }
802:
1.56 paf 803: static void _selectSingle(Request& r, MethodParams& params) {
804: _selectX(r, params,
1.26 paf 805: selectNodeHandler);
806: }
1.1 parser 807:
1.56 paf 808: static void _selectBool(Request& r, MethodParams& params) {
809: _selectX(r, params,
1.26 paf 810: selectBoolHandler);
811: }
1.20 paf 812:
1.56 paf 813: static void _selectNumber(Request& r, MethodParams& params) {
814: _selectX(r, params,
1.26 paf 815: selectNumberHandler);
816: }
1.24 paf 817:
1.56 paf 818: static void _selectString(Request& r, MethodParams& params) {
819: _selectX(r, params,
1.26 paf 820: selectStringHandler);
1.1 parser 821: }
1.20 paf 822:
1.1 parser 823: // constructor
824:
1.56 paf 825: /// @bug one can change const and ruin other's work, we need unchangable VIntConst class
826: MXnode::MXnode(const char* aname, VStateless_class *abase):
827: Methoded(aname?aname:"xnode", abase)
1.44 paf 828: {
1.6 parser 829: /// DOM1 node
830:
831: // Node insertBefore(in Node newChild,in Node refChild) raises(DOMException);
832: add_native_method("insertBefore", Method::CT_DYNAMIC, _insertBefore, 2, 2);
833: // Node replaceChild(in Node newChild,in Node oldChild) raises(DOMException);
834: add_native_method("replaceChild", Method::CT_DYNAMIC, _replaceChild, 2, 2);
835: // Node removeChild(in Node oldChild) raises(DOMException);
836: add_native_method("removeChild", Method::CT_DYNAMIC, _removeChild, 1, 1);
837: // Node appendChild(in Node newChild) raises(DOMException);
838: add_native_method("appendChild", Method::CT_DYNAMIC, _appendChild, 1, 1);
839: // boolean hasChildNodes();
840: add_native_method("hasChildNodes", Method::CT_DYNAMIC, _hasChildNodes, 0, 0);
841: // Node cloneNode(in boolean deep);
842: add_native_method("cloneNode", Method::CT_DYNAMIC, _cloneNode, 1, 1);
843:
844: /// DOM1 element
845:
846: // DOMString getAttribute(in DOMString name);
847: add_native_method("getAttribute", Method::CT_DYNAMIC, _getAttribute, 1, 1);
848: // void setAttribute(in DOMString name, in DOMString value) raises(DOMException);
849: add_native_method("setAttribute", Method::CT_DYNAMIC, _setAttribute, 2, 2);
850: // void removeAttribute(in DOMString name) raises(DOMException);
851: add_native_method("removeAttribute", Method::CT_DYNAMIC, _removeAttribute, 1, 1);
852: // Attr getAttributeNode(in DOMString name);
853: add_native_method("getAttributeNode", Method::CT_DYNAMIC, _getAttributeNode, 1, 1);
854: // Attr setAttributeNode(in Attr newAttr) raises(DOMException);
855: add_native_method("setAttributeNode", Method::CT_DYNAMIC, _setAttributeNode, 1, 1);
856: // Attr removeAttributeNode(in Attr oldAttr) raises(DOMException);
857: add_native_method("removeAttributeNode", Method::CT_DYNAMIC, _removeAttributeNode, 1, 1);
858: // NodeList getElementsByTagName(in DOMString name);
859: add_native_method("getElementsByTagName", Method::CT_DYNAMIC, _getElementsByTagName, 1, 1);
1.39 paf 860: // NodeList getElementsByTagNameNS(in DOMString namespaceURI, in DOMString localName);
861: add_native_method("getElementsByTagNameNS", Method::CT_DYNAMIC, _getElementsByTagNameNS, 2, 2);
1.6 parser 862: // void normalize();
863: add_native_method("normalize", Method::CT_DYNAMIC, _normalize, 0, 0);
1.57 paf 864:
865: /// DOM2 element
866:
1.58 paf 867: // DOMString getAttributeNS(in DOMString namespaceURI, in DOMString localName);
1.57 paf 868: add_native_method("getAttributeNS", Method::CT_DYNAMIC, _getAttributeNS, 2, 2);
1.58 paf 869: // void setAttributeNS(in DOMString namespaceURI, in DOMString qualifiedName, in DOMString value) raises(DOMException);
1.57 paf 870: add_native_method("setAttributeNS", Method::CT_DYNAMIC, _setAttributeNS, 3, 3);
1.58 paf 871: // void removeAttributeNS(in DOMString namespaceURI, in DOMString localName) raises(DOMException);
1.57 paf 872: add_native_method("removeAttributeNS", Method::CT_DYNAMIC, _removeAttributeNS, 2, 2);
1.58 paf 873: // Attr getAttributeNodeNS(in DOMString namespaceURI, in DOMString localName);
1.57 paf 874: add_native_method("getAttributeNodeNS", Method::CT_DYNAMIC, _getAttributeNodeNS, 2, 2);
875: // Attr setAttributeNodeNS(in Attr newAttr) raises(DOMException);
1.72 paf 876: add_native_method("setAttributeNodeNS", Method::CT_DYNAMIC, _setAttributeNode, 1, 1);
1.58 paf 877: // boolean hasAttribute(in DOMString name) raises(DOMException);
1.57 paf 878: add_native_method("hasAttribute", Method::CT_DYNAMIC, _hasAttribute, 1, 1);
1.58 paf 879: // boolean hasAttributeNS(in DOMString namespaceURI, in DOMString localName) raises(DOMException);
1.57 paf 880: add_native_method("hasAttributeNS", Method::CT_DYNAMIC, _hasAttributeNS, 2, 2);
1.78 misha 881: // boolean hasAttributes
882: add_native_method("hasAttributes", Method::CT_DYNAMIC, _hasAttributes, 0, 0);
883:
1.6 parser 884:
885: /// parser
1.1 parser 886: // ^node.select[/some/xpath/query] = hash $.#[dnode]
1.67 paf 887: add_native_method("select", Method::CT_DYNAMIC, _select, 1, 1);
1.1 parser 888:
1.26 paf 889: // ^node.selectSingle[/some/xpath/query] = first node [if any]
1.67 paf 890: add_native_method("selectSingle", Method::CT_DYNAMIC, _selectSingle, 1, 1);
1.26 paf 891: // ^node.selectBool[/some/xpath/query] = bool value [if any]
1.67 paf 892: add_native_method("selectBool", Method::CT_DYNAMIC, _selectBool, 1, 1);
1.26 paf 893: // ^node.selectNumber[/some/xpath/query] = double value [if any]
1.67 paf 894: add_native_method("selectNumber", Method::CT_DYNAMIC, _selectNumber, 1, 1);
1.26 paf 895: // ^node.selectString[/some/xpath/query] = strinv value [if any]
1.67 paf 896: add_native_method("selectString", Method::CT_DYNAMIC, _selectString, 1, 1);
1.20 paf 897:
1.2 parser 898: // consts
899:
1.19 paf 900: #define CONST(name) \
1.72 paf 901: consts.put(String::Body(#name), new VInt(XML_##name))
902: #define CONST2(name, value) \
903: consts.put(String::Body(#name), new VInt(value))
1.2 parser 904:
1.19 paf 905: CONST(ELEMENT_NODE);
1.56 paf 906: CONST(ATTRIBUTE_NODE);
907: CONST(TEXT_NODE);
908: CONST(CDATA_SECTION_NODE);
1.72 paf 909: CONST2(ENTITY_REFERENCE_NODE, XML_ENTITY_REF_NODE);
1.56 paf 910: CONST(ENTITY_NODE);
1.72 paf 911: CONST2(PROCESSING_INSTRUCTION_NODE, XML_PI_NODE);
1.56 paf 912: CONST(COMMENT_NODE);
913: CONST(DOCUMENT_NODE);
914: CONST(DOCUMENT_TYPE_NODE);
1.72 paf 915: CONST2(DOCUMENT_FRAGMENT_NODE, XML_DOCUMENT_FRAG_NODE);
1.56 paf 916: CONST(NOTATION_NODE);
917: }
1.1 parser 918:
1.56 paf 919: #else
1.3 parser 920:
1.1 parser 921: // global variable
922:
1.56 paf 923: DECLARE_CLASS_VAR(xnode, 0, 0); // fictive
1.1 parser 924:
925: #endif
E-mail: