Annotation of parser3/src/classes/xnode.C, revision 1.92
1.1 parser 1: /** @file
2: Parser: @b dom parser class.
3:
1.91 moko 4: Copyright (c) 2001-2015 Art. Lebedev Studio (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.56 paf 10: #include "pa_vmethod_frame.h"
1.1 parser 11:
1.21 paf 12: #include "pa_charset.h"
1.1 parser 13: #include "pa_request.h"
14: #include "pa_vxnode.h"
1.34 paf 15: #include "pa_vxdoc.h"
1.23 paf 16: #include "pa_vvoid.h"
1.60 paf 17: #include "pa_xml_exception.h"
1.76 misha 18: #include "pa_vbool.h"
1.1 parser 19:
20: #include "xnode.h"
1.21 paf 21: #include "libxml/xpath.h"
1.66 paf 22: #include "libxml/xpathInternals.h"
1.21 paf 23:
1.92 ! moko 24: volatile const char * IDENT_XNODE_C="$Id: xnode.C,v 1.91 2015/10/26 01:21:55 moko Exp $" IDENT_XNODE_H;
1.87 moko 25:
1.56 paf 26: // global variable
27:
1.92 ! moko 28: DECLARE_CLASS_VAR(xnode, new MXnode);
1.56 paf 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.88 moko 151: throw XmlException(0, r); // OOM, bad name, things like that
1.72 paf 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: {
1.89 moko 165: if(!namespaceURI || (currentNode->ns && xmlStrEqual(currentNode->ns->href, namespaceURI)) )
1.72 paf 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())
1.88 moko 187: throw XmlException();
1.72 paf 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) {
1.86 misha 275: xmlNode& newChild=as_node(params, 0, "newChild must be node");
276: xmlNode& refChild=as_node(params, 1, "refChild must be node");
277:
1.56 paf 278: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 279: VXdoc& vxdoc=vnode.get_vxdoc();
280:
281: //xmlNode& selfNode=vnode.get_xmlnode();
1.6 parser 282:
1.72 paf 283: xmlNode* retNode=xmlAddPrevSibling(&refChild, &newChild);
284: // write out result
285: writeNode(r, vxdoc, retNode);
1.6 parser 286: }
287:
288: // Node replaceChild(in Node newChild,in Node oldChild) raises(DOMException);
1.56 paf 289: static void _replaceChild(Request& r, MethodParams& params) {
1.86 misha 290: xmlNode& newChild=as_node(params, 0, "newChild must be node");
291: xmlNode& oldChild=as_node(params, 1, "oldChild must be node");
292:
1.56 paf 293: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 294: VXdoc& vxdoc=vnode.get_vxdoc();
295: xmlDoc& xmldoc=vxdoc.get_xmldoc();
296: xmlNode& selfNode=vnode.get_xmlnode();
297:
298: if(newChild.doc!=&xmldoc)
1.74 paf 299: throw Exception("xml.dom",
1.72 paf 300: 0,
301: "WRONG_DOCUMENT_ERR");
302: if(oldChild.doc!=&xmldoc)
1.74 paf 303: throw Exception("xml.dom",
1.72 paf 304: 0,
305: "WRONG_DOCUMENT_ERR");
306:
1.74 paf 307: if(oldChild.parent!=&selfNode)
308: throw Exception("xml.dom",
309: 0,
310: "NOT_FOUND_ERR");
311:
1.72 paf 312: xmlNode* refChild=oldChild.next;
313: xmlUnlinkNode(&oldChild);
314: xmlNode* retNode;
315: if(refChild)
316: retNode=xmlAddPrevSibling(refChild, &newChild);
317: else
318: retNode=xmlAddChild(&selfNode, &newChild);
319:
320: // write out result
321: writeNode(r, vxdoc, retNode);
1.6 parser 322: }
323:
324: // Node removeChild(in Node oldChild) raises(DOMException);
1.56 paf 325: static void _removeChild(Request& r, MethodParams& params) {
1.86 misha 326: xmlNode& oldChild=as_node(params, 0, "refChild must be node");
327:
1.56 paf 328: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 329: VXdoc& vxdoc=vnode.get_vxdoc();
330: xmlDoc& xmldoc=vxdoc.get_xmldoc();
331: // xmlNode& selfNode=vnode.get_xmlnode();
1.6 parser 332:
1.72 paf 333: if(oldChild.doc!=&xmldoc)
1.74 paf 334: throw Exception("xml.dom",
1.72 paf 335: 0,
336: "WRONG_DOCUMENT_ERR");
337:
338: xmlUnlinkNode(&oldChild);
339: // write out result
340: writeNode(r, vxdoc, &oldChild);
1.6 parser 341: }
342:
343: // Node appendChild(in Node newChild) raises(DOMException);
1.56 paf 344: static void _appendChild(Request& r, MethodParams& params) {
1.86 misha 345: xmlNode& newChild=as_node(params, 0, "newChild must be node");
346:
1.56 paf 347: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 348: VXdoc& vxdoc=vnode.get_vxdoc();
349: xmlNode& selfNode=vnode.get_xmlnode();
1.6 parser 350:
1.72 paf 351: xmlNode* retNode=xmlAddChild(&selfNode, &newChild);
352: // write out result
353: writeNode(r, vxdoc, retNode);
1.6 parser 354: }
355:
356: // boolean hasChildNodes();
1.56 paf 357: static void _hasChildNodes(Request& r, MethodParams&) {
358: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 359: xmlNode& node=vnode.get_xmlnode();
1.6 parser 360:
361: // write out result
1.83 misha 362: r.write_no_lang(VBool::get(node.children!=0));
1.6 parser 363: }
364:
365: // Node cloneNode(in boolean deep);
1.56 paf 366: static void _cloneNode(Request& r, MethodParams& params) {
1.86 misha 367: bool deep=params.as_bool(0, "deep must be bool", r);
368:
1.56 paf 369: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 370: xmlNode& selfNode=vnode.get_xmlnode();
371: VXdoc& vxdoc=vnode.get_vxdoc();
372: xmlDoc& xmldoc=vxdoc.get_xmldoc();
1.6 parser 373:
1.72 paf 374: xmlNode* retNode=xmlDocCopyNode(&selfNode, &xmldoc, deep?1: 0);
1.6 parser 375: // write out result
1.72 paf 376: writeNode(r, vxdoc, retNode);
1.6 parser 377: }
378:
379: // DOM1 element
380:
1.72 paf 381: xmlNode& get_self_element(VXnode& vnode) {
382: xmlNode& node=vnode.get_xmlnode();
1.6 parser 383:
1.72 paf 384: if(node.type!=XML_ELEMENT_NODE)
1.77 misha 385: throw Exception(PARSER_RUNTIME,
1.56 paf 386: 0,
1.51 paf 387: "method can only be called on nodes of ELEMENT type");
1.6 parser 388:
1.72 paf 389: return node;
1.6 parser 390: }
391:
1.86 misha 392: // DOMString getAttribute(in DOMString name);
393: static void _getAttribute(Request& r, MethodParams& params) {
394: const xmlChar* name=as_xmlname(r, params, 0);
1.56 paf 395:
1.67 paf 396: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 397: xmlNode& element=get_self_element(vnode);
1.6 parser 398:
1.82 misha 399: // @todo: when name="xmlns"
1.72 paf 400: xmlChar* attribute_value=xmlGetProp(&element, name);
1.6 parser 401: // write out result
1.68 paf 402: r.write_pass_lang(r.transcode(attribute_value));
1.6 parser 403: }
404:
405: // void setAttribute(in DOMString name, in DOMString value) raises(DOMException);
1.56 paf 406: static void _setAttribute(Request& r, MethodParams& params) {
1.86 misha 407: const xmlChar* name=as_xmlname(r, params, 0);
408: const xmlChar* attribute_value=as_xmlchar(r, params, 1, XML_VALUE_MUST_BE_STRING);
409:
1.67 paf 410: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 411: xmlNode& element=get_self_element(vnode);
412:
1.82 misha 413: // @todo: when name="xmlns"
1.72 paf 414: if(!xmlSetProp(&element, name, attribute_value))
1.88 moko 415: throw XmlException(0, r);
1.6 parser 416: }
417:
418: // void removeAttribute(in DOMString name) raises(DOMException);
1.56 paf 419: static void _removeAttribute(Request& r, MethodParams& params) {
1.86 misha 420: const xmlChar* name=as_xmlname(r, params, 0);
421:
1.67 paf 422: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 423: xmlNode& element=get_self_element(vnode);
1.6 parser 424:
1.82 misha 425: // @todo: when name="xmlns"
1.72 paf 426: xmlUnsetProp(&element, name);
1.6 parser 427: }
428:
429: // Attr getAttributeNode(in DOMString name);
1.56 paf 430: static void _getAttributeNode(Request& r, MethodParams& params) {
1.86 misha 431: const xmlChar* localName=as_xmlname(r, params, 0);
432:
1.67 paf 433: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 434: VXdoc& vxdoc=vnode.get_vxdoc();
435: xmlNode& element=get_self_element(vnode);
1.6 parser 436:
1.72 paf 437: if(xmlNode* retNode=pa_getAttributeNodeNS(element, localName, 0)){
1.6 parser 438: // write out result
1.72 paf 439: writeNode(r, vxdoc, retNode);
440: }
1.6 parser 441: }
442:
443: // Attr setAttributeNode(in Attr newAttr) raises(DOMException);
1.72 paf 444: // Attr setAttributeNodeNS(in Attr newAttr) raises(DOMException);
1.56 paf 445: static void _setAttributeNode(Request& r, MethodParams& params) {
1.67 paf 446: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 447: VXdoc& vxdoc=vnode.get_vxdoc();
448: xmlNode& element=get_self_element(vnode);
449: xmlDoc& xmldoc=vxdoc.get_xmldoc();
1.86 misha 450:
1.72 paf 451: xmlAttr& newAttr=as_attr(params, 0, "newAttr must be ATTRIBUTE node");
452:
453: if(newAttr.doc!=&xmldoc)
1.74 paf 454: throw Exception("xml.dom",
1.72 paf 455: 0,
456: "WRONG_DOCUMENT_ERR");
1.6 parser 457:
1.72 paf 458: if(newAttr.parent)
1.74 paf 459: throw Exception("xml.dom",
1.72 paf 460: 0,
461: "INUSE_ATTRIBUTE_ERR");
462:
463: if(xmlNode* retNode=pa_getAttributeNodeNS(element, newAttr.name, pa_xmlGetNsURI((xmlNode*)&newAttr))) {
1.19 paf 464: // write out result
1.72 paf 465: writeNode(r, vxdoc, retNode);
466: xmlUnlinkNode(retNode);
467: }
468:
469: pa_addAttributeNode(element, newAttr);
1.6 parser 470: }
471:
472: // Attr removeAttributeNode(in Attr oldAttr) raises(DOMException);
1.56 paf 473: static void _removeAttributeNode(Request& r, MethodParams& params) {
1.86 misha 474: xmlAttr& oldAttr=as_attr(params, 0, "oldAttr must be ATTRIBUTE node");
475:
1.67 paf 476: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 477: VXdoc& vxdoc=vnode.get_vxdoc();
478: xmlNode& element=get_self_element(vnode);
479:
480: if(oldAttr.parent!=&element)
1.74 paf 481: throw Exception("xml.dom",
1.72 paf 482: 0,
483: "NOT_FOUND_ERR");
1.6 parser 484:
1.72 paf 485: xmlUnlinkNode((xmlNode*)&oldAttr);
486:
487: // write out result
488: writeNode(r, vxdoc, (xmlNode*)&oldAttr);
1.6 parser 489: }
490:
491: // NodeList getElementsByTagName(in DOMString name);
1.86 misha 492: // '*' means all tags
1.56 paf 493: static void _getElementsByTagName(Request& r, MethodParams& params) {
1.86 misha 494: xmlChar* tagName=as_xmlchar(r, params, 0, XML_LOCAL_NAME_MUST_BE_STRING);
495: if(xmlValidateName(tagName, 0) != 0 && strcmp((const char*)tagName, "*") != 0)
496: throw XmlException(0, XML_INVALID_LOCAL_NAME, tagName);
497:
1.67 paf 498: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 499: VXdoc& vxdoc=vnode.get_vxdoc();
500: xmlNode& xmlnode=vnode.get_xmlnode();
1.6 parser 501:
1.56 paf 502: VHash& result=*new VHash;
1.72 paf 503: AccumulateFoundInfo info={&result.hash(), &vxdoc, 0};
504: pa_xmlNamedPreorderTraversal(&xmlnode,
505: 0,
506: tagName,
507: AccumulateFound,
508: &info);
1.6 parser 509:
510: // write out result
511: r.write_no_lang(result);
512: }
513:
1.57 paf 514: // DOM 2
515:
1.58 paf 516: // DOMString getAttributeNS(in DOMString namespaceURI, in DOMString localName);
1.57 paf 517: static void _getAttributeNS(Request& r, MethodParams& params) {
1.86 misha 518: xmlChar* namespaceURI=as_xmlnsuri(r, params, 0);
519: xmlChar* localName=as_xmlname(r, params, 1);
520:
1.67 paf 521: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 522: xmlNode& element=get_self_element(vnode);
1.57 paf 523:
1.72 paf 524: // todo: when name="xmlns"
525: xmlChar* attribute_value=xmlGetNsProp(&element, localName, namespaceURI);
1.57 paf 526: // write out result
1.68 paf 527: r.write_pass_lang(r.transcode(attribute_value));
1.57 paf 528: }
529:
1.72 paf 530:
1.58 paf 531: // void setAttributeNS(in DOMString namespaceURI, in DOMString qualifiedName, in DOMString value) raises(DOMException);
1.57 paf 532: static void _setAttributeNS(Request& r, MethodParams& params) {
1.86 misha 533: const xmlChar* namespaceURI=as_xmlnsuri(r, params, 0);
534: const xmlChar* qualifiedName=as_xmlqname(r, params, 1);
535: const xmlChar* attribute_value=as_xmlchar(r, params, 2, XML_VALUE_MUST_BE_STRING);
536:
1.67 paf 537: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 538: xmlNode& element=get_self_element(vnode);
539: VXdoc& vxdoc=vnode.get_vxdoc();
540: xmlDoc& xmldoc=vxdoc.get_xmldoc();
541:
542: xmlChar* prefix=0;
543: xmlChar* localName=xmlSplitQName2(qualifiedName, &prefix);
544:
1.82 misha 545: // @todo: name=xmlns
1.72 paf 546: xmlAttr* attrNode;
547: if(localName) {
548: xmlNs& ns=pa_xmlMapNs(xmldoc, namespaceURI, prefix);
549:
550: attrNode=xmlSetNsProp(&element, &ns,
551: localName,
552: attribute_value);
553: } else {
554: attrNode=xmlSetProp(&element,
555: qualifiedName/*unqualified, actually*/,
556: attribute_value);
557: }
558:
559: if(!attrNode)
1.88 moko 560: throw XmlException(0, r);
1.57 paf 561: }
562:
1.58 paf 563: // void removeAttributeNS(in DOMString namespaceURI, in DOMString localName) raises(DOMException);
1.57 paf 564: static void _removeAttributeNS(Request& r, MethodParams& params) {
1.86 misha 565: const xmlChar* namespaceURI=as_xmlnsuri(r, params, 0);
566: const xmlChar* localName=as_xmlname(r, params, 1);
567:
1.67 paf 568: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 569: xmlNode& element=get_self_element(vnode);
570: VXdoc& vxdoc=vnode.get_vxdoc();
571: xmlDoc& xmldoc=vxdoc.get_xmldoc();
572:
1.82 misha 573: // @todo: when name="xmlns"
1.72 paf 574: xmlNs& ns=pa_xmlMapNs(xmldoc, namespaceURI, 0);
575: xmlUnsetNsProp(&element, &ns, localName);
1.57 paf 576: }
577:
1.58 paf 578: // Attr getAttributeNodeNS(in DOMString namespaceURI, in DOMString localName);
1.57 paf 579: static void _getAttributeNodeNS(Request& r, MethodParams& params) {
1.86 misha 580: const xmlChar* namespaceURI=as_xmlnsuri(r, params, 0);
581: const xmlChar* localName=as_xmlname(r, params, 1);
582:
1.67 paf 583: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 584: VXdoc& vxdoc=vnode.get_vxdoc();
585: xmlNode& element=get_self_element(vnode);
1.57 paf 586:
1.72 paf 587: if(xmlNode* retNode=pa_getAttributeNodeNS(element, localName, namespaceURI)){
1.57 paf 588: // write out result
1.72 paf 589: writeNode(r, vxdoc, retNode);
590: }
591: }
1.57 paf 592:
1.58 paf 593: // boolean hasAttribute(in DOMString name) raises(DOMException);
1.57 paf 594: static void _hasAttribute(Request& r, MethodParams& params) {
1.86 misha 595: const xmlChar* name=as_xmlname(r, params, 0);
596:
1.67 paf 597: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 598: xmlNode& element=get_self_element(vnode);
1.57 paf 599:
1.82 misha 600: // @todo: when name="xmlns"
1.57 paf 601: // write out result
1.83 misha 602: r.write_no_lang(VBool::get(xmlHasProp(&element, name)!=0));
1.57 paf 603: }
604:
1.58 paf 605: // boolean hasAttributeNS(n DOMString namespaceURI, in DOMString localName) raises(DOMException);
1.57 paf 606: static void _hasAttributeNS(Request& r, MethodParams& params) {
1.86 misha 607: const xmlChar* namespaceURI=as_xmlnsuri(r, params, 0);
608: const xmlChar* localName=as_xmlname(r, params, 1);
609:
1.67 paf 610: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 611: xmlNode& element=get_self_element(vnode);
1.57 paf 612:
613: // write out result
1.83 misha 614: r.write_no_lang(VBool::get(xmlHasNsProp(&element, localName, namespaceURI)!=0));
1.57 paf 615: }
616:
1.78 misha 617: // boolean hasAttributes
618: static void _hasAttributes(Request& r, MethodParams&) {
619: VXnode& vnode=GET_SELF(r, VXnode);
620: xmlNode& element=get_self_element(vnode);
621:
622: // write out result
1.83 misha 623: r.write_no_lang(VBool::get(element.properties!=0));
1.78 misha 624: }
625:
1.86 misha 626: // NodeList getElementsByTagNameNS(in DOMString namespaceURI, in DOMString localName);
627: // '*' as namespaceURI means get all namespaces
628: // '*' as localName means get all tags
1.56 paf 629: static void _getElementsByTagNameNS(Request& r, MethodParams& params) {
1.86 misha 630: xmlChar* namespaceURI=as_xmlchar(r, params, 0, XML_NAMESPACEURI_MUST_BE_STRING);
631:
632: xmlChar* localName=as_xmlchar(r, params, 1, XML_LOCAL_NAME_MUST_BE_STRING);
633: if(xmlValidateName(localName, 0) != 0 && strcmp((const char*)localName, "*") != 0)
634: throw XmlException(0, XML_INVALID_LOCAL_NAME, localName);
635:
1.67 paf 636: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 637: VXdoc& vdoc=vnode.get_vxdoc();
638: xmlDoc& xmldoc=vdoc.get_xmldoc();
1.39 paf 639:
1.56 paf 640: VHash& result=*new VHash;
1.72 paf 641: AccumulateFoundInfo info={&result.hash(), &vdoc, 0};
642: pa_xmlNamedPreorderTraversal((xmlNode*)&xmldoc,
643: namespaceURI,
644: localName,
645: AccumulateFound,
646: &info);
1.39 paf 647:
648: // write out result
649: r.write_no_lang(result);
650: }
651:
1.72 paf 652:
1.6 parser 653: // void normalize();
1.72 paf 654: static void _normalize(Request&, MethodParams&) {
655: /*maybe someday
1.56 paf 656: VXnode& vnode=GET_SELF(r, VXnode);
1.72 paf 657: xmlNode& selfNode=vnode.get_xmlnode();
1.6 parser 658:
1.19 paf 659: gdome_n_normalize(selfNode, &exc);
660: if(exc)
1.60 paf 661: throw XmlException(0, exc);
1.72 paf 662: */
1.6 parser 663: }
1.25 paf 664:
1.66 paf 665: #ifndef DOXYGEN
666: struct Register_one_ns_info {
667: Request* r;
668: xmlXPathContextPtr ctxt;
669: };
670: #endif
671: static void register_one_ns(
672: HashStringValue::key_type key,
673: HashStringValue::value_type value,
674: Register_one_ns_info* info) {
675: if(const String* svalue=value->get_string())
676: xmlXPathRegisterNs(info->ctxt,
1.72 paf 677: info->r->transcode(key),
678: info->r->transcode(*svalue));
1.66 paf 679: else
1.77 misha 680: throw Exception(PARSER_RUNTIME,
1.66 paf 681: new String(key, String::L_TAINTED),
682: "value is %s, must be string or number", value->type());
683: }
1.56 paf 684: static void _selectX(Request& r, MethodParams& params,
685: void (*handler)(Request& r,
1.26 paf 686: const String& expression,
687: xmlXPathObject_auto_ptr res,
1.67 paf 688: VXdoc& xdoc,
1.72 paf 689: Value*& result))
690: {
1.56 paf 691: VXnode& vnode=GET_SELF(r, VXnode);
1.74 paf 692: xmlNode& xmlnode=vnode.get_xmlnode();
1.72 paf 693: VXdoc& vdoc=vnode.get_vxdoc();
694: xmlDoc& xmldoc=vdoc.get_xmldoc();
1.1 parser 695:
696: // expression
1.56 paf 697: const String& expression=params.as_string(0, "expression must be string");
1.72 paf 698: xmlXPathContext_auto_ptr ctxt(xmlXPathNewContext(&xmldoc));
1.67 paf 699: {
1.66 paf 700: Register_one_ns_info info={&r, ctxt.get()};
1.75 paf 701: vdoc.search_namespaces.hash().for_each<Register_one_ns_info*>(register_one_ns, &info);
1.66 paf 702: }
1.74 paf 703: ctxt->node=&xmlnode;
1.25 paf 704: /*error to stderr for now*/
705: xmlXPathObject_auto_ptr res(
1.72 paf 706: xmlXPathEvalExpression(r.transcode(expression), ctxt.get()));
1.28 paf 707:
1.72 paf 708: if(xmlHaveGenericErrors())
1.88 moko 709: throw XmlException(0, r);
1.25 paf 710:
1.56 paf 711: Value* result=0;
1.25 paf 712: if(res.get())
1.72 paf 713: handler(r, expression, res, vdoc, result);
1.44 paf 714: if(result)
1.26 paf 715: r.write_no_lang(*result);
716: }
1.25 paf 717:
1.72 paf 718: static void selectNodesHandler(Request&,
1.56 paf 719: const String& expression,
720: xmlXPathObject_auto_ptr res,
1.67 paf 721: VXdoc& xdoc,
1.56 paf 722: Value*& result) {
723: VHash& vhash=*new VHash; result=&vhash;
1.26 paf 724: switch(res->type) {
725: case XPATH_UNDEFINED:
726: break;
727: case XPATH_NODESET:
1.40 paf 728: if(res->nodesetval)
729: if(int size=res->nodesetval->nodeNr) {
1.56 paf 730: HashStringValue& hash=vhash.hash();
731: for(int i=0; i<size; i++)
732: hash.put(
1.59 paf 733: String::Body::Format(i),
1.72 paf 734: &xdoc.wrap(*res->nodesetval->nodeTab[i]));
1.1 parser 735: }
1.26 paf 736: break;
737: default:
1.77 misha 738: throw Exception(PARSER_RUNTIME,
1.26 paf 739: &expression,
740: "wrong xmlXPathEvalExpression result type (%d)", res->type);
741: break; // never
742: }
743: }
744:
1.56 paf 745: static void selectNodeHandler(Request& r,
746: const String& expression,
1.67 paf 747: xmlXPathObject_auto_ptr res,
748: VXdoc& xdoc,
749: Value*& result) {
1.26 paf 750: switch(res->type) {
751: case XPATH_UNDEFINED:
752: break;
753: case XPATH_NODESET:
1.80 misha 754: if(res->nodesetval && res->nodesetval->nodeNr) { // empty result strangely has NODESET res->type
1.26 paf 755: if(res->nodesetval->nodeNr>1)
1.77 misha 756: throw Exception(PARSER_RUNTIME,
1.56 paf 757: &expression,
758: "resulted not in a single node (%d)", res->nodesetval->nodeNr);
1.26 paf 759:
1.72 paf 760: result=&xdoc.wrap(*res->nodesetval->nodeTab[0]);
1.25 paf 761: }
1.26 paf 762: break;
763: case XPATH_BOOLEAN:
1.83 misha 764: result=&VBool::get(res->boolval!=0);
1.26 paf 765: break;
766: case XPATH_NUMBER:
1.56 paf 767: result=new VDouble(res->floatval);
1.26 paf 768: break;
769: case XPATH_STRING:
1.56 paf 770: result=new VString(r.transcode((xmlChar*)res->stringval));
1.26 paf 771: break;
772: default:
1.77 misha 773: throw Exception(PARSER_RUNTIME,
1.26 paf 774: &expression,
775: "wrong xmlXPathEvalExpression result type (%d)", res->type);
776: }
777: }
778:
1.62 paf 779: static void selectBoolHandler(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_BOOLEAN:
1.83 misha 786: result=&VBool::get(res->boolval!=0);
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: }
1.1 parser 799:
1.62 paf 800: static void selectNumberHandler(Request&,
1.56 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_NUMBER:
1.56 paf 807: result=new VDouble(res->floatval);
1.26 paf 808: break;
809: case XPATH_NODESET:
1.40 paf 810: if(!(res->nodesetval && res->nodesetval->nodeNr))
1.26 paf 811: break;
812: // else[nodeset] fall down to default
813: default:
1.77 misha 814: throw Exception(PARSER_RUNTIME,
1.26 paf 815: &expression,
816: "wrong xmlXPathEvalExpression result type (%d)", res->type);
817: break; // never
818: }
819: }
820:
1.56 paf 821: static void selectStringHandler(Request& r,
1.26 paf 822: const String& expression,
823: xmlXPathObject_auto_ptr res,
1.67 paf 824: VXdoc& /*xdoc*/,
1.56 paf 825: Value*& result) {
1.26 paf 826: switch(res->type) {
827: case XPATH_UNDEFINED:
828: break;
829: case XPATH_STRING:
1.56 paf 830: result=new VString(r.transcode((xmlChar*)res->stringval));
1.26 paf 831: break;
832: case XPATH_NODESET:
1.40 paf 833: if(!(res->nodesetval && res->nodesetval->nodeNr))
1.26 paf 834: break;
835: // else[nodeset] fall down to default
836: default:
1.77 misha 837: throw Exception(PARSER_RUNTIME,
1.26 paf 838: &expression,
839: "wrong xmlXPathEvalExpression result type (%d)", res->type);
840: break; // never
1.1 parser 841: }
842: }
1.25 paf 843:
1.56 paf 844: static void _select(Request& r, MethodParams& params) {
845: _selectX(r, params,
1.26 paf 846: selectNodesHandler);
847: }
848:
1.56 paf 849: static void _selectSingle(Request& r, MethodParams& params) {
850: _selectX(r, params,
1.26 paf 851: selectNodeHandler);
852: }
1.1 parser 853:
1.56 paf 854: static void _selectBool(Request& r, MethodParams& params) {
855: _selectX(r, params,
1.26 paf 856: selectBoolHandler);
857: }
1.20 paf 858:
1.56 paf 859: static void _selectNumber(Request& r, MethodParams& params) {
860: _selectX(r, params,
1.26 paf 861: selectNumberHandler);
862: }
1.24 paf 863:
1.56 paf 864: static void _selectString(Request& r, MethodParams& params) {
865: _selectX(r, params,
1.26 paf 866: selectStringHandler);
1.1 parser 867: }
1.20 paf 868:
1.1 parser 869: // constructor
870:
1.56 paf 871: /// @bug one can change const and ruin other's work, we need unchangable VIntConst class
872: MXnode::MXnode(const char* aname, VStateless_class *abase):
873: Methoded(aname?aname:"xnode", abase)
1.44 paf 874: {
1.6 parser 875: /// DOM1 node
876:
877: // Node insertBefore(in Node newChild,in Node refChild) raises(DOMException);
878: add_native_method("insertBefore", Method::CT_DYNAMIC, _insertBefore, 2, 2);
879: // Node replaceChild(in Node newChild,in Node oldChild) raises(DOMException);
880: add_native_method("replaceChild", Method::CT_DYNAMIC, _replaceChild, 2, 2);
881: // Node removeChild(in Node oldChild) raises(DOMException);
882: add_native_method("removeChild", Method::CT_DYNAMIC, _removeChild, 1, 1);
883: // Node appendChild(in Node newChild) raises(DOMException);
884: add_native_method("appendChild", Method::CT_DYNAMIC, _appendChild, 1, 1);
885: // boolean hasChildNodes();
886: add_native_method("hasChildNodes", Method::CT_DYNAMIC, _hasChildNodes, 0, 0);
887: // Node cloneNode(in boolean deep);
888: add_native_method("cloneNode", Method::CT_DYNAMIC, _cloneNode, 1, 1);
889:
890: /// DOM1 element
891:
892: // DOMString getAttribute(in DOMString name);
893: add_native_method("getAttribute", Method::CT_DYNAMIC, _getAttribute, 1, 1);
894: // void setAttribute(in DOMString name, in DOMString value) raises(DOMException);
895: add_native_method("setAttribute", Method::CT_DYNAMIC, _setAttribute, 2, 2);
896: // void removeAttribute(in DOMString name) raises(DOMException);
897: add_native_method("removeAttribute", Method::CT_DYNAMIC, _removeAttribute, 1, 1);
898: // Attr getAttributeNode(in DOMString name);
899: add_native_method("getAttributeNode", Method::CT_DYNAMIC, _getAttributeNode, 1, 1);
900: // Attr setAttributeNode(in Attr newAttr) raises(DOMException);
901: add_native_method("setAttributeNode", Method::CT_DYNAMIC, _setAttributeNode, 1, 1);
902: // Attr removeAttributeNode(in Attr oldAttr) raises(DOMException);
903: add_native_method("removeAttributeNode", Method::CT_DYNAMIC, _removeAttributeNode, 1, 1);
904: // NodeList getElementsByTagName(in DOMString name);
905: add_native_method("getElementsByTagName", Method::CT_DYNAMIC, _getElementsByTagName, 1, 1);
1.39 paf 906: // NodeList getElementsByTagNameNS(in DOMString namespaceURI, in DOMString localName);
907: add_native_method("getElementsByTagNameNS", Method::CT_DYNAMIC, _getElementsByTagNameNS, 2, 2);
1.6 parser 908: // void normalize();
909: add_native_method("normalize", Method::CT_DYNAMIC, _normalize, 0, 0);
1.57 paf 910:
911: /// DOM2 element
912:
1.58 paf 913: // DOMString getAttributeNS(in DOMString namespaceURI, in DOMString localName);
1.57 paf 914: add_native_method("getAttributeNS", Method::CT_DYNAMIC, _getAttributeNS, 2, 2);
1.58 paf 915: // void setAttributeNS(in DOMString namespaceURI, in DOMString qualifiedName, in DOMString value) raises(DOMException);
1.57 paf 916: add_native_method("setAttributeNS", Method::CT_DYNAMIC, _setAttributeNS, 3, 3);
1.58 paf 917: // void removeAttributeNS(in DOMString namespaceURI, in DOMString localName) raises(DOMException);
1.57 paf 918: add_native_method("removeAttributeNS", Method::CT_DYNAMIC, _removeAttributeNS, 2, 2);
1.58 paf 919: // Attr getAttributeNodeNS(in DOMString namespaceURI, in DOMString localName);
1.57 paf 920: add_native_method("getAttributeNodeNS", Method::CT_DYNAMIC, _getAttributeNodeNS, 2, 2);
921: // Attr setAttributeNodeNS(in Attr newAttr) raises(DOMException);
1.72 paf 922: add_native_method("setAttributeNodeNS", Method::CT_DYNAMIC, _setAttributeNode, 1, 1);
1.58 paf 923: // boolean hasAttribute(in DOMString name) raises(DOMException);
1.57 paf 924: add_native_method("hasAttribute", Method::CT_DYNAMIC, _hasAttribute, 1, 1);
1.58 paf 925: // boolean hasAttributeNS(in DOMString namespaceURI, in DOMString localName) raises(DOMException);
1.57 paf 926: add_native_method("hasAttributeNS", Method::CT_DYNAMIC, _hasAttributeNS, 2, 2);
1.78 misha 927: // boolean hasAttributes
928: add_native_method("hasAttributes", Method::CT_DYNAMIC, _hasAttributes, 0, 0);
929:
1.6 parser 930:
931: /// parser
1.1 parser 932: // ^node.select[/some/xpath/query] = hash $.#[dnode]
1.67 paf 933: add_native_method("select", Method::CT_DYNAMIC, _select, 1, 1);
1.1 parser 934:
1.26 paf 935: // ^node.selectSingle[/some/xpath/query] = first node [if any]
1.67 paf 936: add_native_method("selectSingle", Method::CT_DYNAMIC, _selectSingle, 1, 1);
1.26 paf 937: // ^node.selectBool[/some/xpath/query] = bool value [if any]
1.67 paf 938: add_native_method("selectBool", Method::CT_DYNAMIC, _selectBool, 1, 1);
1.26 paf 939: // ^node.selectNumber[/some/xpath/query] = double value [if any]
1.67 paf 940: add_native_method("selectNumber", Method::CT_DYNAMIC, _selectNumber, 1, 1);
1.26 paf 941: // ^node.selectString[/some/xpath/query] = strinv value [if any]
1.67 paf 942: add_native_method("selectString", Method::CT_DYNAMIC, _selectString, 1, 1);
1.20 paf 943:
1.2 parser 944: // consts
945:
1.90 moko 946: #define CONST(name) consts.put(#name, new VInt(XML_##name))
947: #define CONST2(name, value) consts.put(#name, new VInt(value))
1.2 parser 948:
1.19 paf 949: CONST(ELEMENT_NODE);
1.56 paf 950: CONST(ATTRIBUTE_NODE);
951: CONST(TEXT_NODE);
952: CONST(CDATA_SECTION_NODE);
1.72 paf 953: CONST2(ENTITY_REFERENCE_NODE, XML_ENTITY_REF_NODE);
1.56 paf 954: CONST(ENTITY_NODE);
1.72 paf 955: CONST2(PROCESSING_INSTRUCTION_NODE, XML_PI_NODE);
1.56 paf 956: CONST(COMMENT_NODE);
957: CONST(DOCUMENT_NODE);
958: CONST(DOCUMENT_TYPE_NODE);
1.72 paf 959: CONST2(DOCUMENT_FRAGMENT_NODE, XML_DOCUMENT_FRAG_NODE);
1.56 paf 960: CONST(NOTATION_NODE);
961: }
1.1 parser 962:
1.56 paf 963: #else
1.3 parser 964:
1.1 parser 965: // global variable
966:
1.92 ! moko 967: DECLARE_CLASS_VAR(xnode, 0); // fictive
1.1 parser 968:
969: #endif
E-mail: