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