Annotation of parser3/src/classes/xdoc.C, revision 1.4

1.1       parser      1: /** @file
1.2       parser      2:        Parser: @b xdoc parser class.
1.1       parser      3: 
                      4:        Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com)
                      5:        Author: Alexander Petrosyan <paf@design.ru> (http://design.ru/paf)
                      6: 
1.4     ! parser      7:        $Id: xdoc.C,v 1.3 2001/09/27 07:26:27 parser Exp $
1.1       parser      8: */
                      9: #include "classes.h"
                     10: #ifdef XML
                     11: 
                     12: #include "pa_request.h"
                     13: #include "pa_vxdoc.h"
                     14: #include "pa_xslt_stylesheet_manager.h"
                     15: #include "pa_stylesheet_connection.h"
                     16: #include "pa_vfile.h"
                     17: #include "xnode.h"
                     18: 
                     19: #include <strstream>
                     20: #include <Include/PlatformDefinitions.hpp>
                     21: #include <util/PlatformUtils.hpp>
                     22: #include <XalanTransformer/XalanTransformer.hpp>
                     23: #include <XalanTransformer/XalanParsedSource.hpp>
                     24: #include <XMLSupport/FormatterToXML.hpp>
                     25: #include <XMLSupport/FormatterToHTML.hpp>
                     26: #include <XMLSupport/FormatterToText.hpp>
                     27: #include <XMLSupport/FormatterTreeWalker.hpp>
                     28: #include <PlatformSupport/XalanFileOutputStream.hpp>
                     29: #include <PlatformSupport/XalanOutputStreamPrintWriter.hpp>
                     30: #include <PlatformSupport/DOMStringPrintWriter.hpp>
1.2       parser     31: #include <XalanDOM/XalanElement.hpp>
                     32: #include <XalanDOM/XalanNodeList.hpp>
1.1       parser     33: 
                     34: // defines
                     35: 
                     36: #define XDOC_CLASS_NAME "xdoc"
                     37: 
                     38: #define XDOC_OUTPUT_METHOD_OPTION_NAME "method"
                     39: #define XDOC_OUTPUT_METHOD_OPTION_VALUE_XML "xml"
                     40: #define XDOC_OUTPUT_METHOD_OPTION_VALUE_HTML "html"
                     41: #define XDOC_OUTPUT_METHOD_OPTION_VALUE_TEXT "text"
                     42: 
                     43: #define XDOC_OUTPUT_ENCODING_OPTION_NAME "encoding"
                     44: 
                     45: #define XDOC_OUTPUT_DEFAULT_INDENT 4
                     46: 
                     47: // class
                     48: 
                     49: class MXdoc : public MXnode {
                     50: public: // VStateless_class
                     51:        Value *create_new_value(Pool& pool) { return new(pool) VXdoc(pool); }
                     52: 
                     53: public:
                     54:        MXdoc(Pool& pool);
                     55: 
                     56: public: // Methoded
                     57:        bool used_directly() { return true; }
                     58: };
                     59: 
                     60: // methods
                     61: 
                     62: class ParserStringXalanOutputStream: public XalanOutputStream {
                     63: public:
                     64:        
                     65:        explicit ParserStringXalanOutputStream(String& astring) : fstring(astring) {}
                     66: 
                     67: protected: // XalanOutputStream
                     68: 
                     69:        virtual void writeData(const char *theBuffer, unsigned long theBufferLength) {
                     70:                char *copy=(char *)fstring.malloc((size_t)theBufferLength);
                     71:                memcpy(copy, theBuffer, (size_t)theBufferLength);
1.2       parser     72:                fstring.APPEND_CLEAN(copy, (size_t)theBufferLength, "xdoc", 0);
1.1       parser     73:        }
                     74: 
                     75:        virtual void doFlush() {}
                     76: 
                     77: private:
                     78: 
                     79:        String& fstring;
                     80:        
                     81: };
                     82: 
                     83: static void create_optioned_listener(
                     84:                                                                         const char *& content_type, const char *& charset, FormatterListener *& listener, 
                     85:                                                                         Pool& pool, 
                     86:                                                                         const String& method_name, MethodParams *params, int index, Writer& writer) {
                     87:        // default encoding from pool
                     88:        const String *scharset=&pool.get_charset();
                     89:        const String *method=0;
                     90:        XalanDOMString xalan_encoding;
                     91: 
                     92:        if(params->size()>index) {
                     93:                Value& voptions=params->as_no_junction(index, "options must not be code");
                     94:                if(voptions.is_defined()) {
                     95:                        if(Hash *options=voptions.get_hash()) {
                     96:                                // $.method[xml|html|text]
                     97:                                if(Value *vmethod=static_cast<Value *>(options->get(*new(pool) 
                     98:                                        String(pool, XDOC_OUTPUT_METHOD_OPTION_NAME))))
                     99:                                        method=&vmethod->as_string();
                    100: 
                    101:                                // $.encoding[windows-1251|...]
                    102:                                if(Value *vencoding=static_cast<Value *>(options->get(*new(pool) 
                    103:                                        String(pool, XDOC_OUTPUT_ENCODING_OPTION_NAME)))) {
                    104:                                        scharset=&vencoding->as_string();
                    105:                                }
                    106:                        } else
                    107:                                PTHROW(0, 0,
                    108:                                        &method_name,
                    109:                                        "options must be hash");
                    110:                }
                    111:        }
                    112: 
                    113:        xalan_encoding.append(charset=scharset->cstr());
                    114:        if(!method/*default='xml'*/ || *method == XDOC_OUTPUT_METHOD_OPTION_VALUE_XML) {
                    115:                content_type="text/xml";
                    116:                listener=new FormatterToXML(writer,
                    117:                        XalanDOMString(),  // version
                    118:                        true, // doIndent
                    119:                        XDOC_OUTPUT_DEFAULT_INDENT, // indent 
                    120:                        xalan_encoding  // encoding
                    121:                );
                    122:        } else if(*method == XDOC_OUTPUT_METHOD_OPTION_VALUE_HTML) {
                    123:                content_type="text/html";
                    124:                listener=new FormatterToHTML(writer,
                    125:                        xalan_encoding,  // encoding
                    126:                        XalanDOMString(),  // mediaType 
                    127:                        XalanDOMString(),  // doctypeSystem; String to be printed at the top of the document 
                    128:                        XalanDOMString(),  // doctypePublic  
                    129:                        true, // doIndent 
                    130:                        XDOC_OUTPUT_DEFAULT_INDENT // indent 
                    131:                );
                    132:        } else if(*method == XDOC_OUTPUT_METHOD_OPTION_VALUE_TEXT) {
                    133:                content_type="text/plain";
                    134:                listener=new FormatterToText(writer,
                    135:                        xalan_encoding  // encoding
                    136:                );
                    137:        } else
                    138:                PTHROW(0, 0,
                    139:                        method,
                    140:                        XDOC_OUTPUT_METHOD_OPTION_NAME " option is invalid; valid methods are: "
                    141:                                "'" XDOC_OUTPUT_METHOD_OPTION_VALUE_XML "', "
                    142:                                "'" XDOC_OUTPUT_METHOD_OPTION_VALUE_HTML "', "
                    143:                                "'" XDOC_OUTPUT_METHOD_OPTION_VALUE_TEXT "'");                  
                    144: 
                    145:        // never reached
                    146: }
                    147: 
                    148: static void _save(Request& r, const String& method_name, MethodParams *params) {
                    149:        Pool& pool=r.pool();
                    150:        VXnode& vnode=*static_cast<VXnode *>(r.self);
                    151: 
                    152:        // filespec
                    153:        const String& file_name=params->as_string(0, "file name must not be code");
                    154:        const char *filespec=r.absolute(file_name).cstr(String::UL_FILE_SPEC);
                    155:        
                    156:        // node
                    157:        XalanNode& node=vnode.get_node(pool, &method_name);
                    158: 
                    159:        try {
                    160:                XalanFileOutputStream stream(XalanDOMString(filespec, strlen(filespec)));
                    161:                XalanOutputStreamPrintWriter writer(stream);
                    162:                const char *content_type, *charset;
                    163:                FormatterListener *formatterListener;
                    164:                create_optioned_listener(content_type, charset, formatterListener, 
                    165:                        pool, method_name, params, 1, writer);
                    166:                FormatterTreeWalker treeWalker(*formatterListener);
                    167:                treeWalker.traverse(&node); // Walk that node and produce the XML...
                    168:        } catch(const XSLException& e) {
                    169:                r._throw(&method_name, e);
                    170:        }
                    171: }
                    172: 
                    173: static void _string(Request& r, const String& method_name, MethodParams *params) {
                    174:        Pool& pool=r.pool();
                    175:        VXnode& vnode=*static_cast<VXnode *>(r.self);
                    176: 
                    177:        // node
                    178:        XalanNode& node=vnode.get_node(pool, &method_name);
                    179: 
                    180:        try {
                    181:                String parserString=*new(pool) String(pool);
                    182:                ParserStringXalanOutputStream stream(parserString);
                    183:                XalanOutputStreamPrintWriter writer(stream);
                    184:                const char *content_type, *charset;
                    185:                FormatterListener *formatterListener;
                    186:                create_optioned_listener(content_type, charset, formatterListener, 
                    187:                        pool, method_name, params, 0, writer);
                    188:                FormatterTreeWalker treeWalker(*formatterListener);
                    189:                treeWalker.traverse(&node); // Walk that node and produce the XML...
                    190: 
                    191:                // write out result
                    192:                r.write_no_lang(parserString);
                    193:        } catch(const XSLException& e) {
                    194:                r._throw(&method_name, e);
                    195:        }
                    196: }
                    197: 
                    198: 
                    199: static void _file(Request& r, const String& method_name, MethodParams *params) {
                    200:        Pool& pool=r.pool();
                    201:        VXnode& vnode=*static_cast<VXnode *>(r.self);
                    202: 
                    203:        // node
                    204:        XalanNode& node=vnode.get_node(pool, &method_name);
                    205: 
                    206:        try {
                    207:                String& parserString=*new(pool) String(pool);
                    208:                ParserStringXalanOutputStream stream(parserString);
                    209:                XalanOutputStreamPrintWriter writer(stream);
                    210:                const char *content_type, *charset;
                    211:                FormatterListener *formatterListener;
                    212:                create_optioned_listener(content_type, charset, formatterListener, 
                    213:                        pool, method_name, params, 0, writer);
                    214:                FormatterTreeWalker treeWalker(*formatterListener);
                    215:                treeWalker.traverse(&node); // Walk that node and produce the XML...
                    216: 
                    217:                // write out result
                    218:                VFile& vfile=*new(pool) VFile(pool);
                    219:                const char *cstr=parserString.cstr();
                    220:                String *scontent_type=new(pool) String(pool, content_type);
                    221:                Value *vcontent_type;
                    222:                if(charset) {
                    223:                        VHash *vhcontent_type=new(pool) VHash(pool);
                    224:                        vhcontent_type->hash().put(*value_name, new(pool) VString(*scontent_type));
                    225:                        String *scharset=new(pool) String(pool, charset);
                    226:                        vhcontent_type->hash().put(*new(pool) String(pool, "charset"), new(pool) VString(*scharset));
                    227:                        vcontent_type=vhcontent_type;
                    228:                } else
                    229:                        vcontent_type=new(pool) VString(*scontent_type);
                    230:                vfile.set(false/*tainted*/, cstr, strlen(cstr), 0/*file_name*/, vcontent_type);
                    231:                r.write_no_lang(vfile);
                    232:        } catch(const XSLException& e) {
                    233:                r._throw(&method_name, e);
                    234:        }
                    235: }
                    236: 
                    237: static void _set(Request& r, const String& method_name, MethodParams *params) {
                    238:        Pool& pool=r.pool();
                    239:        VXdoc& vdom=*static_cast<VXdoc *>(r.self);
                    240: 
                    241:        Value& vxml=params->as_junction(0, "xml must be code");
                    242:        Temp_lang temp_lang(r, String::UL_XML);
                    243:        const String& xml=r.process(vxml).as_string();
                    244: 
                    245:        std::istrstream stream(xml.cstr());
                    246:        const XalanParsedSource* parsedSource;
                    247:        int error=vdom.transformer().parseSource(&stream, parsedSource);
                    248: 
                    249:        if(error)
                    250:                PTHROW(0, 0,
                    251:                        &method_name,
                    252:                        vdom.transformer().getLastError());
                    253: 
                    254:        // replace any previous parsed source
                    255:        vdom.set_parsed_source(*parsedSource);
                    256: }
                    257: 
                    258: static void _load(Request& r, const String& method_name, MethodParams *params) {
                    259:        Pool& pool=r.pool();
                    260:        VXdoc& vdom=*static_cast<VXdoc *>(r.self);
                    261: 
                    262:        // filespec
                    263:        const String& file_name=params->as_string(0, "file name must not be code");
                    264:        const char *filespec=r.absolute(file_name).cstr(String::UL_FILE_SPEC);
                    265:        
                    266:        const XalanParsedSource* parsedSource;
                    267:        int error=vdom.transformer().parseSource(filespec, parsedSource);
                    268: 
                    269:        if(error)
                    270:                PTHROW(0, 0,
                    271:                        &file_name,
                    272:                        vdom.transformer().getLastError());
                    273: 
                    274:        // replace any previous parsed source
                    275:        vdom.set_parsed_source(*parsedSource);
                    276: }
                    277: 
                    278: static void add_xslt_param(const Hash::Key& aattribute, Hash::Val *ameaning, 
                    279:                                                   void *info) {
                    280:        XalanTransformer& transformer=*static_cast<XalanTransformer *>(info);
                    281:        const char *attribute_cstr=aattribute.cstr();
                    282:        const char *meaning_cstr=static_cast<Value *>(ameaning)->as_string().cstr();
                    283: 
                    284:        transformer.setStylesheetParam(
                    285:                XalanDOMString(attribute_cstr),  
                    286:                XalanDOMString(meaning_cstr));
                    287: }
                    288: static void _xslt(Request& r, const String& method_name, MethodParams *params) {
                    289:        Pool& pool=r.pool();
                    290:        VXdoc& vdom=*static_cast<VXdoc *>(r.self);
                    291: 
                    292:        // params
                    293:        if(params->size()>1) {
                    294:                Value& vparams=params->as_no_junction(1, "transform parameters parameter must not be code");
                    295:                if(vparams.is_defined())
                    296:                        if(Hash *params=vparams.get_hash())
                    297:                                params->for_each(add_xslt_param, &vdom.transformer());
                    298:                        else
                    299:                                PTHROW(0, 0,
                    300:                                        &method_name,
                    301:                                        "transform parameters parameter must be hash");
                    302:        }
                    303: 
                    304:        // source
                    305:        const XalanParsedSource &parsed_source=vdom.get_parsed_source(pool, &method_name);
                    306: 
                    307:        // stylesheet
                    308:        const String& stylesheet_file_name=params->as_string(0, "file name must not be code");
                    309:        const String& stylesheet_filespec=r.absolute(stylesheet_file_name);
                    310:        //_asm int 3;
                    311:        Stylesheet_connection& connection=XSLT_stylesheet_manager->get_connection(stylesheet_filespec);
                    312: 
                    313:        // target
                    314:        XalanDocument* target=vdom.parser_liaison().createDocument();
                    315:        XSLTResultTarget domResultTarget(target);
                    316: 
                    317:        // transform
                    318:        int error=vdom.transformer().transform(
                    319:                parsed_source, 
                    320:                &connection.stylesheet(), 
                    321:                domResultTarget);
                    322:        connection.close();
                    323:        if(error)
                    324:                PTHROW(0, 0,
                    325:                        &stylesheet_file_name,
                    326:                        vdom.transformer().getLastError());
                    327: 
                    328:        // write out result
                    329:        VXdoc& result=*new(pool) VXdoc(pool);
                    330:        result.set_document(*target);
                    331:        r.write_no_lang(result);
                    332: }
                    333: 
1.2       parser    334: static void _getElementById(Request& r, const String& method_name, MethodParams *params) {
                    335:        Pool& pool=r.pool();
                    336:        VXdoc& vdoc=*static_cast<VXdoc *>(r.self);
                    337: 
                    338:        // elementId
                    339:        const char *elementId=params->as_string(0, "elementID must not be code").cstr(String::UL_AS_IS);
                    340: 
                    341:        if(XalanElement *element=
                    342:                vdoc.get_document(pool, &method_name).getElementById(XalanDOMString(elementId))) {
                    343:                // write out result
                    344:                VXnode& result=*new(pool) VXnode(pool, element);
                    345:                r.write_no_lang(result);
                    346:        }
                    347: }
1.4     ! parser    348: /*
1.2       parser    349: static void _getElementsByTagName(Request& r, const String& method_name, MethodParams *params) {
                    350:        Pool& pool=r.pool();
                    351:        VXdoc& vdoc=*static_cast<VXdoc *>(r.self);
                    352: 
                    353:        // tagname
                    354:        const char *tagname=params->as_string(0, "tagname must not be code").cstr(String::UL_AS_IS);
                    355: 
                    356:        VHash& result=*new(pool) VHash(pool);
                    357:        if(const XalanNodeList *nodes=
                    358:                vdoc.get_document(pool, &method_name).getElementsByTagName(XalanDOMString(tagname))) {
                    359:                for(int i=0; i<nodes->getLength(); i++) {
                    360:                        String& skey=*new(pool) String(pool);
                    361:                        {
                    362:                                char *buf=(char *)pool.malloc(MAX_NUMBER);
                    363:                                snprintf(buf, MAX_NUMBER, "%d", i);
                    364:                                skey << buf;
                    365:                        }
                    366: 
                    367:                        result.hash().put(skey, new(pool) VXnode(pool, nodes->item(i)));
                    368:                }
                    369:        }
                    370: 
                    371:        // write out result
                    372:        r.write_no_lang(result);
                    373: }
                    374: 
                    375: static void _getElementsByTagNameNS(Request& r, const String& method_name, MethodParams *params) {
                    376:        Pool& pool=r.pool();
                    377:        VXdoc& vdoc=*static_cast<VXdoc *>(r.self);
                    378: 
                    379:        // namespaceURI;localName
                    380:        const char *namespaceURI=params->as_string(0, "namespaceURI must not be code").cstr(String::UL_AS_IS);
                    381:        const char *localName=params->as_string(0, "localName must not be code").cstr(String::UL_AS_IS);
                    382: 
                    383:        VHash& result=*new(pool) VHash(pool);
                    384:        if(const XalanNodeList *nodes=
                    385:                vdoc.get_document(pool, &method_name).getElementsByTagNameNS(
                    386:                        XalanDOMString(namespaceURI), XalanDOMString(localName))) {
                    387:                for(int i=0; i<nodes->getLength(); i++) {
                    388:                        String& skey=*new(pool) String(pool);
                    389:                        {
                    390:                                char *buf=(char *)pool.malloc(MAX_NUMBER);
                    391:                                snprintf(buf, MAX_NUMBER, "%d", i);
                    392:                                skey << buf;
                    393:                        }
                    394: 
                    395:                        result.hash().put(skey, new(pool) VXnode(pool, nodes->item(i)));
                    396:                }
                    397:        }
                    398: 
                    399:        // write out result
                    400:        r.write_no_lang(result);
                    401: }
1.4     ! parser    402: */
1.1       parser    403: // constructor
                    404: 
                    405: MXdoc::MXdoc(Pool& apool) : MXnode(apool) {
                    406:        set_name(*NEW String(pool(), XDOC_CLASS_NAME));
                    407: 
1.2       parser    408:        // ^xdoc.save[some.xml]
                    409:        // ^xdoc.save[some.xml;options hash]
1.1       parser    410:        add_native_method("save", Method::CT_DYNAMIC, _save, 1, 2);
                    411: 
1.2       parser    412:        // ^xdoc.string[] <doc/>
                    413:        // ^xdoc.string[options hash] <doc/>
1.1       parser    414:        add_native_method("string", Method::CT_DYNAMIC, _string, 0, 1);
                    415: 
1.2       parser    416:        // ^xdoc.file[] file with "<doc/>"
                    417:        // ^xdoc.file[options hash] file with "<doc/>"
1.1       parser    418:        add_native_method("file", Method::CT_DYNAMIC, _file, 0, 1);
                    419: 
1.2       parser    420:        // ^xdoc::set[<some>xml</some>]
1.1       parser    421:        add_native_method("set", Method::CT_DYNAMIC, _set, 1, 1);
                    422: 
1.2       parser    423:        // ^xdoc::load[some.xml]
1.1       parser    424:        add_native_method("load", Method::CT_DYNAMIC, _load, 1, 1);
                    425: 
1.2       parser    426:        // ^xdoc.xslt[stylesheet file_name]
                    427:        // ^xdoc.xslt[stylesheet file_name;params hash]
1.1       parser    428:        add_native_method("xslt", Method::CT_DYNAMIC, _xslt, 1, 2);
1.2       parser    429: 
                    430:        // ^xdoc.getElementById[elementId]
                    431:        add_native_method("getElementById", Method::CT_DYNAMIC, _getElementById, 1, 1);
1.4     ! parser    432: /*     
1.3       parser    433:        // ^xdoc.getElementsByTagName[tagname]
1.2       parser    434:        add_native_method("getElementsByTagName", Method::CT_DYNAMIC, _getElementsByTagName, 1, 1);
                    435: 
                    436:        // ^xdoc.getElementsByTagNameNS[namespaceURI;localName] = array of nodes
                    437:        add_native_method("getElementsByTagNameNS", Method::CT_DYNAMIC, _getElementsByTagNameNS, 2, 2);
1.4     ! parser    438: */
1.1       parser    439: }
                    440: // global variable
                    441: 
                    442: Methoded *Xdoc_class;
                    443: 
                    444: // creator
                    445: 
                    446: #endif
                    447: 
                    448: Methoded *MXdoc_create(Pool& pool) {
                    449:        return 
                    450: #ifdef XML
                    451:                Xdoc_class=new(pool) MXdoc(pool);
                    452: #else
                    453:                0
                    454: #endif
                    455:        ;
                    456: }

E-mail: