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

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

E-mail: