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