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