Annotation of parser3/src/classes/xnode.C, revision 1.77
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.77 ! misha 10: static const char * const IDENT_XNODE_C="$Date: 2007/02/03 18:08:38 $";
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.72 paf 333: bool result=node.children!=0;
1.56 paf 334: r.write_no_lang(*new VBool(result));
1.6 parser 335: }
336:
337: // Node cloneNode(in boolean deep);
1.56 paf 338: static void _cloneNode(Request& r, MethodParams& params) {
339: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 340: xmlNode& selfNode=vnode.get_xmlnode();
341: VXdoc& vxdoc=vnode.get_vxdoc();
342: xmlDoc& xmldoc=vxdoc.get_xmldoc();
1.6 parser 343:
1.56 paf 344: bool deep=params.as_bool(0, "deep must be bool", r);
1.6 parser 345:
1.72 paf 346: xmlNode* retNode=xmlDocCopyNode(&selfNode, &xmldoc, deep?1: 0);
1.6 parser 347: // write out result
1.72 paf 348: writeNode(r, vxdoc, retNode);
1.6 parser 349: }
350:
351: // DOM1 element
352:
1.72 paf 353: xmlNode& get_self_element(VXnode& vnode) {
354: xmlNode& node=vnode.get_xmlnode();
1.6 parser 355:
1.72 paf 356: if(node.type!=XML_ELEMENT_NODE)
1.77 ! misha 357: throw Exception(PARSER_RUNTIME,
1.56 paf 358: 0,
1.51 paf 359: "method can only be called on nodes of ELEMENT type");
1.6 parser 360:
1.72 paf 361: return node;
1.6 parser 362: }
363:
1.56 paf 364:
365: static void _getAttribute(Request& r, MethodParams& params) {
1.67 paf 366: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 367: xmlNode& element=get_self_element(vnode);
368: const xmlChar* name=as_xmlchar(r, params, 0, "name must be string");
1.6 parser 369:
1.72 paf 370: // todo: when name="xmlns"
371: xmlChar* attribute_value=xmlGetProp(&element, name);
1.6 parser 372: // write out result
1.68 paf 373: r.write_pass_lang(r.transcode(attribute_value));
1.6 parser 374: }
375:
376: // void setAttribute(in DOMString name, in DOMString value) raises(DOMException);
1.56 paf 377: static void _setAttribute(Request& r, MethodParams& params) {
1.67 paf 378: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 379: xmlNode& element=get_self_element(vnode);
380: const xmlChar* name=as_xmlchar(r, params, 0, "name must be string");
381: const xmlChar* attribute_value=as_xmlchar(r, params, 1, "value must be string");
382:
383: // todo: when name="xmlns"
384: if(!xmlSetProp(&element, name, attribute_value))
385: throw XmlException(0);
1.6 parser 386: }
387:
388: // void removeAttribute(in DOMString name) raises(DOMException);
1.56 paf 389: static void _removeAttribute(Request& r, MethodParams& params) {
1.67 paf 390: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 391: xmlNode& element=get_self_element(vnode);
392: const xmlChar* name=as_xmlchar(r, params, 0, "name must be string");
1.6 parser 393:
1.72 paf 394: // todo: when name="xmlns"
395: xmlUnsetProp(&element, name);
1.6 parser 396: }
397:
398: // Attr getAttributeNode(in DOMString name);
1.56 paf 399: static void _getAttributeNode(Request& r, MethodParams& params) {
1.67 paf 400: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 401: VXdoc& vxdoc=vnode.get_vxdoc();
402: xmlNode& element=get_self_element(vnode);
403: const xmlChar* localName=as_xmlchar(r, params, 0, "name must be string");
1.6 parser 404:
1.72 paf 405: if(xmlNode* retNode=pa_getAttributeNodeNS(element, localName, 0)){
1.6 parser 406: // write out result
1.72 paf 407: writeNode(r, vxdoc, retNode);
408: }
1.6 parser 409: }
410:
411: // Attr setAttributeNode(in Attr newAttr) raises(DOMException);
1.72 paf 412: // Attr setAttributeNodeNS(in Attr newAttr) raises(DOMException);
1.56 paf 413: static void _setAttributeNode(Request& r, MethodParams& params) {
1.67 paf 414: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 415: VXdoc& vxdoc=vnode.get_vxdoc();
416: xmlNode& element=get_self_element(vnode);
417: xmlDoc& xmldoc=vxdoc.get_xmldoc();
418: xmlAttr& newAttr=as_attr(params, 0, "newAttr must be ATTRIBUTE node");
419:
420: if(newAttr.doc!=&xmldoc)
1.74 paf 421: throw Exception("xml.dom",
1.72 paf 422: 0,
423: "WRONG_DOCUMENT_ERR");
1.6 parser 424:
1.72 paf 425: if(newAttr.parent)
1.74 paf 426: throw Exception("xml.dom",
1.72 paf 427: 0,
428: "INUSE_ATTRIBUTE_ERR");
429:
430: if(xmlNode* retNode=pa_getAttributeNodeNS(element, newAttr.name, pa_xmlGetNsURI((xmlNode*)&newAttr))) {
1.19 paf 431: // write out result
1.72 paf 432: writeNode(r, vxdoc, retNode);
433: xmlUnlinkNode(retNode);
434: }
435:
436: pa_addAttributeNode(element, newAttr);
1.6 parser 437: }
438:
439: // Attr removeAttributeNode(in Attr oldAttr) raises(DOMException);
1.56 paf 440: static void _removeAttributeNode(Request& r, MethodParams& params) {
1.67 paf 441: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 442: VXdoc& vxdoc=vnode.get_vxdoc();
443: xmlNode& element=get_self_element(vnode);
444: xmlAttr& oldAttr=as_attr(params, 0, "oldAttr must be ATTRIBUTE node");
445:
446: if(oldAttr.parent!=&element)
1.74 paf 447: throw Exception("xml.dom",
1.72 paf 448: 0,
449: "NOT_FOUND_ERR");
1.6 parser 450:
1.72 paf 451: xmlUnlinkNode((xmlNode*)&oldAttr);
452:
453: // write out result
454: writeNode(r, vxdoc, (xmlNode*)&oldAttr);
1.6 parser 455: }
456:
457: // NodeList getElementsByTagName(in DOMString name);
1.56 paf 458: static void _getElementsByTagName(Request& r, MethodParams& params) {
1.67 paf 459: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 460: VXdoc& vxdoc=vnode.get_vxdoc();
461: xmlNode& xmlnode=vnode.get_xmlnode();
1.6 parser 462:
1.72 paf 463: xmlChar* tagName=as_xmlchar(r, params, 0, "name must be string");
1.6 parser 464:
1.56 paf 465: VHash& result=*new VHash;
1.72 paf 466: AccumulateFoundInfo info={&result.hash(), &vxdoc, 0};
467: pa_xmlNamedPreorderTraversal(&xmlnode,
468: 0,
469: tagName,
470: AccumulateFound,
471: &info);
1.6 parser 472:
473: // write out result
474: r.write_no_lang(result);
475: }
476:
1.57 paf 477: // DOM 2
478:
1.58 paf 479: // DOMString getAttributeNS(in DOMString namespaceURI, in DOMString localName);
1.57 paf 480: static void _getAttributeNS(Request& r, MethodParams& params) {
1.67 paf 481: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 482: xmlNode& element=get_self_element(vnode);
1.57 paf 483:
1.72 paf 484: xmlChar* namespaceURI=as_xmlchar(r, params, 0, "namespaceURI must be string");
485: xmlChar* localName=as_xmlchar(r, params, 1, "localName must be string");
1.57 paf 486:
1.72 paf 487: // todo: when name="xmlns"
488: xmlChar* attribute_value=xmlGetNsProp(&element, localName, namespaceURI);
1.57 paf 489: // write out result
1.68 paf 490: r.write_pass_lang(r.transcode(attribute_value));
1.57 paf 491: }
492:
1.72 paf 493:
1.58 paf 494: // void setAttributeNS(in DOMString namespaceURI, in DOMString qualifiedName, in DOMString value) raises(DOMException);
1.57 paf 495: static void _setAttributeNS(Request& r, MethodParams& params) {
1.67 paf 496: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 497: xmlNode& element=get_self_element(vnode);
498: VXdoc& vxdoc=vnode.get_vxdoc();
499: xmlDoc& xmldoc=vxdoc.get_xmldoc();
500: const xmlChar* namespaceURI=as_xmlchar(r, params, 0, "namespaceURI must be string");
501: const xmlChar* qualifiedName=as_xmlchar(r, params, 1, "qualifiedName must be string");
502: const xmlChar* attribute_value=as_xmlchar(r, params, 2, "value must be string");
503:
504: xmlChar* prefix=0;
505: xmlChar* localName=xmlSplitQName2(qualifiedName, &prefix);
506:
507: // todo: name=xmlns
508: xmlAttr* attrNode;
509: if(localName) {
510: xmlNs& ns=pa_xmlMapNs(xmldoc, namespaceURI, prefix);
511:
512: attrNode=xmlSetNsProp(&element, &ns,
513: localName,
514: attribute_value);
515: } else {
516: attrNode=xmlSetProp(&element,
517: qualifiedName/*unqualified, actually*/,
518: attribute_value);
519: }
520:
521: if(!attrNode)
522: throw XmlException(0);
1.57 paf 523: }
524:
1.58 paf 525: // void removeAttributeNS(in DOMString namespaceURI, in DOMString localName) raises(DOMException);
1.57 paf 526: static void _removeAttributeNS(Request& r, MethodParams& params) {
1.67 paf 527: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 528: xmlNode& element=get_self_element(vnode);
529: VXdoc& vxdoc=vnode.get_vxdoc();
530: xmlDoc& xmldoc=vxdoc.get_xmldoc();
531: const xmlChar* namespaceURI=as_xmlchar(r, params, 0, "namespaceURI must be string");
532: const xmlChar* localName=as_xmlchar(r, params, 1, "localName must be string");
533:
534: // todo: when name="xmlns"
535: xmlNs& ns=pa_xmlMapNs(xmldoc, namespaceURI, 0);
536: xmlUnsetNsProp(&element, &ns, localName);
1.57 paf 537: }
538:
1.58 paf 539: // Attr getAttributeNodeNS(in DOMString namespaceURI, in DOMString localName);
1.57 paf 540: static void _getAttributeNodeNS(Request& r, MethodParams& params) {
1.67 paf 541: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 542: VXdoc& vxdoc=vnode.get_vxdoc();
543: xmlNode& element=get_self_element(vnode);
544: const xmlChar* namespaceURI=as_xmlchar(r, params, 0, "namespaceURI must be string");
545: const xmlChar* localName=as_xmlchar(r, params, 1, "localName must be string");
1.57 paf 546:
1.72 paf 547: if(xmlNode* retNode=pa_getAttributeNodeNS(element, localName, namespaceURI)){
1.57 paf 548: // write out result
1.72 paf 549: writeNode(r, vxdoc, retNode);
550: }
551: }
1.57 paf 552:
1.58 paf 553: // boolean hasAttribute(in DOMString name) raises(DOMException);
1.57 paf 554: static void _hasAttribute(Request& r, MethodParams& params) {
1.67 paf 555: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 556: xmlNode& element=get_self_element(vnode);
1.57 paf 557:
1.72 paf 558: const xmlChar* name=as_xmlchar(r, params, 0, "name must be string");
1.57 paf 559:
1.72 paf 560: xmlChar* prop=xmlGetProp(&element, name);
561: // todo: when name="xmlns"
1.57 paf 562: // write out result
1.72 paf 563: r.write_no_lang(*new VBool(prop!=0));
1.57 paf 564: }
565:
1.58 paf 566: // boolean hasAttributeNS(n DOMString namespaceURI, in DOMString localName) raises(DOMException);
1.57 paf 567: static void _hasAttributeNS(Request& r, MethodParams& params) {
1.67 paf 568: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 569: xmlNode& element=get_self_element(vnode);
1.57 paf 570:
1.72 paf 571: const xmlChar* namespaceURI=as_xmlchar(r, params, 0, "namespaceURI must be string");
572: const xmlChar* localName=as_xmlchar(r, params, 1, "localName must be string");
1.57 paf 573:
1.72 paf 574: xmlChar* prop=xmlGetNsProp(&element, localName, namespaceURI);
1.57 paf 575: // write out result
1.72 paf 576: r.write_no_lang(*new VBool(prop!=0));
1.57 paf 577: }
578:
1.56 paf 579: static void _getElementsByTagNameNS(Request& r, MethodParams& params) {
1.67 paf 580: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 581: VXdoc& vdoc=vnode.get_vxdoc();
582: xmlDoc& xmldoc=vdoc.get_xmldoc();
1.39 paf 583:
584: // namespaceURI;localName
1.72 paf 585: xmlChar* namespaceURI=as_xmlchar(r, params, 0, "namespaceURI must be string");
586: xmlChar* localName=as_xmlchar(r, params, 1, "name must be string");
1.39 paf 587:
1.56 paf 588: VHash& result=*new VHash;
1.72 paf 589: AccumulateFoundInfo info={&result.hash(), &vdoc, 0};
590: pa_xmlNamedPreorderTraversal((xmlNode*)&xmldoc,
591: namespaceURI,
592: localName,
593: AccumulateFound,
594: &info);
1.39 paf 595:
596: // write out result
597: r.write_no_lang(result);
598: }
599:
1.72 paf 600:
1.6 parser 601: // void normalize();
1.72 paf 602: static void _normalize(Request&, MethodParams&) {
603: /*maybe someday
1.56 paf 604: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 605: xmlNode& selfNode=vnode.get_xmlnode();
1.6 parser 606:
1.19 paf 607: gdome_n_normalize(selfNode, &exc);
608: if(exc)
1.60 paf 609: throw XmlException(0, exc);
1.72 paf 610: */
1.6 parser 611: }
1.25 paf 612:
1.66 paf 613: #ifndef DOXYGEN
614: struct Register_one_ns_info {
615: Request* r;
616: xmlXPathContextPtr ctxt;
617: };
618: #endif
619: static void register_one_ns(
620: HashStringValue::key_type key,
621: HashStringValue::value_type value,
622: Register_one_ns_info* info) {
623: if(const String* svalue=value->get_string())
624: xmlXPathRegisterNs(info->ctxt,
1.72 paf 625: info->r->transcode(key),
626: info->r->transcode(*svalue));
1.66 paf 627: else
1.77 ! misha 628: throw Exception(PARSER_RUNTIME,
1.66 paf 629: new String(key, String::L_TAINTED),
630: "value is %s, must be string or number", value->type());
631: }
1.56 paf 632: static void _selectX(Request& r, MethodParams& params,
633: void (*handler)(Request& r,
1.26 paf 634: const String& expression,
635: xmlXPathObject_auto_ptr res,
1.67 paf 636: VXdoc& xdoc,
1.72 paf 637: Value*& result))
638: {
1.56 paf 639: VXnode& vnode=GET_SELF(r, VXnode);
1.74 paf 640: xmlNode& xmlnode=vnode.get_xmlnode();
1.72 paf 641: VXdoc& vdoc=vnode.get_vxdoc();
642: xmlDoc& xmldoc=vdoc.get_xmldoc();
1.1 parser 643:
644: // expression
1.56 paf 645: const String& expression=params.as_string(0, "expression must be string");
1.72 paf 646: xmlXPathContext_auto_ptr ctxt(xmlXPathNewContext(&xmldoc));
1.67 paf 647: {
1.66 paf 648: Register_one_ns_info info={&r, ctxt.get()};
1.75 paf 649: vdoc.search_namespaces.hash().for_each<Register_one_ns_info*>(register_one_ns, &info);
1.66 paf 650: }
1.74 paf 651: ctxt->node=&xmlnode;
1.25 paf 652: /*error to stderr for now*/
653: xmlXPathObject_auto_ptr res(
1.72 paf 654: xmlXPathEvalExpression(r.transcode(expression), ctxt.get()));
1.28 paf 655:
1.72 paf 656: if(xmlHaveGenericErrors())
657: throw XmlException(0);
1.25 paf 658:
1.56 paf 659: Value* result=0;
1.25 paf 660: if(res.get())
1.72 paf 661: handler(r, expression, res, vdoc, result);
1.44 paf 662: if(result)
1.26 paf 663: r.write_no_lang(*result);
664: }
1.25 paf 665:
1.72 paf 666: static void selectNodesHandler(Request&,
1.56 paf 667: const String& expression,
668: xmlXPathObject_auto_ptr res,
1.67 paf 669: VXdoc& xdoc,
1.56 paf 670: Value*& result) {
671: VHash& vhash=*new VHash; result=&vhash;
1.26 paf 672: switch(res->type) {
673: case XPATH_UNDEFINED:
674: break;
675: case XPATH_NODESET:
1.40 paf 676: if(res->nodesetval)
677: if(int size=res->nodesetval->nodeNr) {
1.56 paf 678: HashStringValue& hash=vhash.hash();
679: for(int i=0; i<size; i++)
680: hash.put(
1.59 paf 681: String::Body::Format(i),
1.72 paf 682: &xdoc.wrap(*res->nodesetval->nodeTab[i]));
1.1 parser 683: }
1.26 paf 684: break;
685: default:
1.77 ! misha 686: throw Exception(PARSER_RUNTIME,
1.26 paf 687: &expression,
688: "wrong xmlXPathEvalExpression result type (%d)", res->type);
689: break; // never
690: }
691: }
692:
1.56 paf 693: static void selectNodeHandler(Request& r,
694: const String& expression,
1.67 paf 695: xmlXPathObject_auto_ptr res,
696: VXdoc& xdoc,
697: Value*& result) {
1.26 paf 698: switch(res->type) {
699: case XPATH_UNDEFINED:
700: break;
701: case XPATH_NODESET:
1.40 paf 702: if(res->nodesetval && res->nodesetval->nodeNr) { // empty result strangly has NODESET res->type
1.26 paf 703: if(res->nodesetval->nodeNr>1)
1.77 ! misha 704: throw Exception(PARSER_RUNTIME,
1.56 paf 705: &expression,
706: "resulted not in a single node (%d)", res->nodesetval->nodeNr);
1.26 paf 707:
1.72 paf 708: result=&xdoc.wrap(*res->nodesetval->nodeTab[0]);
1.25 paf 709: }
1.26 paf 710: break;
711: case XPATH_BOOLEAN:
1.56 paf 712: result=new VBool(res->boolval!=0);
1.26 paf 713: break;
714: case XPATH_NUMBER:
1.56 paf 715: result=new VDouble(res->floatval);
1.26 paf 716: break;
717: case XPATH_STRING:
1.56 paf 718: result=new VString(r.transcode((xmlChar*)res->stringval));
1.26 paf 719: break;
720: default:
1.77 ! misha 721: throw Exception(PARSER_RUNTIME,
1.26 paf 722: &expression,
723: "wrong xmlXPathEvalExpression result type (%d)", res->type);
724: }
725: }
726:
1.62 paf 727: static void selectBoolHandler(Request&,
1.56 paf 728: const String& expression,
729: xmlXPathObject_auto_ptr res,
1.67 paf 730: VXdoc& /*xdoc*/,
1.56 paf 731: Value*& result) {
1.26 paf 732: switch(res->type) {
733: case XPATH_BOOLEAN:
1.56 paf 734: result=new VBool(res->boolval!=0);
1.26 paf 735: break;
736: case XPATH_NODESET:
1.40 paf 737: if(!(res->nodesetval && res->nodesetval->nodeNr))
1.26 paf 738: break;
739: // else[nodeset] fall down to default
740: default:
1.77 ! misha 741: throw Exception(PARSER_RUNTIME,
1.26 paf 742: &expression,
743: "wrong xmlXPathEvalExpression result type (%d)", res->type);
744: break; // never
745: }
746: }
1.1 parser 747:
1.62 paf 748: static void selectNumberHandler(Request&,
1.56 paf 749: const String& expression,
750: xmlXPathObject_auto_ptr res,
1.67 paf 751: VXdoc& /*xdoc*/,
1.56 paf 752: Value*& result) {
1.26 paf 753: switch(res->type) {
754: case XPATH_NUMBER:
1.56 paf 755: result=new VDouble(res->floatval);
1.26 paf 756: break;
757: case XPATH_NODESET:
1.40 paf 758: if(!(res->nodesetval && res->nodesetval->nodeNr))
1.26 paf 759: break;
760: // else[nodeset] fall down to default
761: default:
1.77 ! misha 762: throw Exception(PARSER_RUNTIME,
1.26 paf 763: &expression,
764: "wrong xmlXPathEvalExpression result type (%d)", res->type);
765: break; // never
766: }
767: }
768:
1.56 paf 769: static void selectStringHandler(Request& r,
1.26 paf 770: const String& expression,
771: xmlXPathObject_auto_ptr res,
1.67 paf 772: VXdoc& /*xdoc*/,
1.56 paf 773: Value*& result) {
1.26 paf 774: switch(res->type) {
775: case XPATH_UNDEFINED:
776: break;
777: case XPATH_STRING:
1.56 paf 778: result=new VString(r.transcode((xmlChar*)res->stringval));
1.26 paf 779: break;
780: case XPATH_NODESET:
1.40 paf 781: if(!(res->nodesetval && res->nodesetval->nodeNr))
1.26 paf 782: break;
783: // else[nodeset] fall down to default
784: default:
1.77 ! misha 785: throw Exception(PARSER_RUNTIME,
1.26 paf 786: &expression,
787: "wrong xmlXPathEvalExpression result type (%d)", res->type);
788: break; // never
1.1 parser 789: }
790: }
1.25 paf 791:
1.56 paf 792: static void _select(Request& r, MethodParams& params) {
793: _selectX(r, params,
1.26 paf 794: selectNodesHandler);
795: }
796:
1.56 paf 797: static void _selectSingle(Request& r, MethodParams& params) {
798: _selectX(r, params,
1.26 paf 799: selectNodeHandler);
800: }
1.1 parser 801:
1.56 paf 802: static void _selectBool(Request& r, MethodParams& params) {
803: _selectX(r, params,
1.26 paf 804: selectBoolHandler);
805: }
1.20 paf 806:
1.56 paf 807: static void _selectNumber(Request& r, MethodParams& params) {
808: _selectX(r, params,
1.26 paf 809: selectNumberHandler);
810: }
1.24 paf 811:
1.56 paf 812: static void _selectString(Request& r, MethodParams& params) {
813: _selectX(r, params,
1.26 paf 814: selectStringHandler);
1.1 parser 815: }
1.20 paf 816:
1.1 parser 817: // constructor
818:
1.56 paf 819: /// @bug one can change const and ruin other's work, we need unchangable VIntConst class
820: MXnode::MXnode(const char* aname, VStateless_class *abase):
821: Methoded(aname?aname:"xnode", abase)
1.44 paf 822: {
1.6 parser 823: /// DOM1 node
824:
825: // Node insertBefore(in Node newChild,in Node refChild) raises(DOMException);
826: add_native_method("insertBefore", Method::CT_DYNAMIC, _insertBefore, 2, 2);
827: // Node replaceChild(in Node newChild,in Node oldChild) raises(DOMException);
828: add_native_method("replaceChild", Method::CT_DYNAMIC, _replaceChild, 2, 2);
829: // Node removeChild(in Node oldChild) raises(DOMException);
830: add_native_method("removeChild", Method::CT_DYNAMIC, _removeChild, 1, 1);
831: // Node appendChild(in Node newChild) raises(DOMException);
832: add_native_method("appendChild", Method::CT_DYNAMIC, _appendChild, 1, 1);
833: // boolean hasChildNodes();
834: add_native_method("hasChildNodes", Method::CT_DYNAMIC, _hasChildNodes, 0, 0);
835: // Node cloneNode(in boolean deep);
836: add_native_method("cloneNode", Method::CT_DYNAMIC, _cloneNode, 1, 1);
837:
838: /// DOM1 element
839:
840: // DOMString getAttribute(in DOMString name);
841: add_native_method("getAttribute", Method::CT_DYNAMIC, _getAttribute, 1, 1);
842: // void setAttribute(in DOMString name, in DOMString value) raises(DOMException);
843: add_native_method("setAttribute", Method::CT_DYNAMIC, _setAttribute, 2, 2);
844: // void removeAttribute(in DOMString name) raises(DOMException);
845: add_native_method("removeAttribute", Method::CT_DYNAMIC, _removeAttribute, 1, 1);
846: // Attr getAttributeNode(in DOMString name);
847: add_native_method("getAttributeNode", Method::CT_DYNAMIC, _getAttributeNode, 1, 1);
848: // Attr setAttributeNode(in Attr newAttr) raises(DOMException);
849: add_native_method("setAttributeNode", Method::CT_DYNAMIC, _setAttributeNode, 1, 1);
850: // Attr removeAttributeNode(in Attr oldAttr) raises(DOMException);
851: add_native_method("removeAttributeNode", Method::CT_DYNAMIC, _removeAttributeNode, 1, 1);
852: // NodeList getElementsByTagName(in DOMString name);
853: add_native_method("getElementsByTagName", Method::CT_DYNAMIC, _getElementsByTagName, 1, 1);
1.39 paf 854: // NodeList getElementsByTagNameNS(in DOMString namespaceURI, in DOMString localName);
855: add_native_method("getElementsByTagNameNS", Method::CT_DYNAMIC, _getElementsByTagNameNS, 2, 2);
1.6 parser 856: // void normalize();
857: add_native_method("normalize", Method::CT_DYNAMIC, _normalize, 0, 0);
1.57 paf 858:
859: /// DOM2 element
860:
1.58 paf 861: // DOMString getAttributeNS(in DOMString namespaceURI, in DOMString localName);
1.57 paf 862: add_native_method("getAttributeNS", Method::CT_DYNAMIC, _getAttributeNS, 2, 2);
1.58 paf 863: // void setAttributeNS(in DOMString namespaceURI, in DOMString qualifiedName, in DOMString value) raises(DOMException);
1.57 paf 864: add_native_method("setAttributeNS", Method::CT_DYNAMIC, _setAttributeNS, 3, 3);
1.58 paf 865: // void removeAttributeNS(in DOMString namespaceURI, in DOMString localName) raises(DOMException);
1.57 paf 866: add_native_method("removeAttributeNS", Method::CT_DYNAMIC, _removeAttributeNS, 2, 2);
1.58 paf 867: // Attr getAttributeNodeNS(in DOMString namespaceURI, in DOMString localName);
1.57 paf 868: add_native_method("getAttributeNodeNS", Method::CT_DYNAMIC, _getAttributeNodeNS, 2, 2);
869: // Attr setAttributeNodeNS(in Attr newAttr) raises(DOMException);
1.72 paf 870: add_native_method("setAttributeNodeNS", Method::CT_DYNAMIC, _setAttributeNode, 1, 1);
1.58 paf 871: // boolean hasAttribute(in DOMString name) raises(DOMException);
1.57 paf 872: add_native_method("hasAttribute", Method::CT_DYNAMIC, _hasAttribute, 1, 1);
1.58 paf 873: // boolean hasAttributeNS(in DOMString namespaceURI, in DOMString localName) raises(DOMException);
1.57 paf 874: add_native_method("hasAttributeNS", Method::CT_DYNAMIC, _hasAttributeNS, 2, 2);
1.6 parser 875:
876: /// parser
1.1 parser 877: // ^node.select[/some/xpath/query] = hash $.#[dnode]
1.67 paf 878: add_native_method("select", Method::CT_DYNAMIC, _select, 1, 1);
1.1 parser 879:
1.26 paf 880: // ^node.selectSingle[/some/xpath/query] = first node [if any]
1.67 paf 881: add_native_method("selectSingle", Method::CT_DYNAMIC, _selectSingle, 1, 1);
1.26 paf 882: // ^node.selectBool[/some/xpath/query] = bool value [if any]
1.67 paf 883: add_native_method("selectBool", Method::CT_DYNAMIC, _selectBool, 1, 1);
1.26 paf 884: // ^node.selectNumber[/some/xpath/query] = double value [if any]
1.67 paf 885: add_native_method("selectNumber", Method::CT_DYNAMIC, _selectNumber, 1, 1);
1.26 paf 886: // ^node.selectString[/some/xpath/query] = strinv value [if any]
1.67 paf 887: add_native_method("selectString", Method::CT_DYNAMIC, _selectString, 1, 1);
1.20 paf 888:
1.2 parser 889: // consts
890:
1.19 paf 891: #define CONST(name) \
1.72 paf 892: consts.put(String::Body(#name), new VInt(XML_##name))
893: #define CONST2(name, value) \
894: consts.put(String::Body(#name), new VInt(value))
1.2 parser 895:
1.19 paf 896: CONST(ELEMENT_NODE);
1.56 paf 897: CONST(ATTRIBUTE_NODE);
898: CONST(TEXT_NODE);
899: CONST(CDATA_SECTION_NODE);
1.72 paf 900: CONST2(ENTITY_REFERENCE_NODE, XML_ENTITY_REF_NODE);
1.56 paf 901: CONST(ENTITY_NODE);
1.72 paf 902: CONST2(PROCESSING_INSTRUCTION_NODE, XML_PI_NODE);
1.56 paf 903: CONST(COMMENT_NODE);
904: CONST(DOCUMENT_NODE);
905: CONST(DOCUMENT_TYPE_NODE);
1.72 paf 906: CONST2(DOCUMENT_FRAGMENT_NODE, XML_DOCUMENT_FRAG_NODE);
1.56 paf 907: CONST(NOTATION_NODE);
908: }
1.1 parser 909:
1.56 paf 910: #else
1.3 parser 911:
1.1 parser 912: // global variable
913:
1.56 paf 914: DECLARE_CLASS_VAR(xnode, 0, 0); // fictive
1.1 parser 915:
916: #endif
E-mail: