Annotation of parser3/src/classes/xnode.C, revision 1.74.8.1

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

E-mail: