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