Annotation of parser3/src/classes/xdoc.C, revision 1.9
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.9 ! parser 7: $Id: xdoc.C,v 1.8 2001/10/05 11:21:10 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>
1.5 parser 22: #include <util/TransENameMap.hpp>
1.1 parser 23: #include <XalanTransformer/XalanTransformer.hpp>
24: #include <XalanTransformer/XalanParsedSource.hpp>
1.9 ! parser 25: # include <XalanTransformer/XalanDefaultParsedSource.hpp>
! 26: # include <XalanSourceTree/XalanSourceTreeDocument.hpp>
1.1 parser 27: #include <XMLSupport/FormatterToXML.hpp>
28: #include <XMLSupport/FormatterToHTML.hpp>
29: #include <XMLSupport/FormatterToText.hpp>
30: #include <XMLSupport/FormatterTreeWalker.hpp>
31: #include <PlatformSupport/XalanFileOutputStream.hpp>
32: #include <PlatformSupport/XalanOutputStreamPrintWriter.hpp>
33: #include <PlatformSupport/DOMStringPrintWriter.hpp>
1.2 parser 34: #include <XalanDOM/XalanElement.hpp>
35: #include <XalanDOM/XalanNodeList.hpp>
1.1 parser 36:
37: // defines
38:
39: #define XDOC_CLASS_NAME "xdoc"
40:
41: #define XDOC_OUTPUT_METHOD_OPTION_NAME "method"
42: #define XDOC_OUTPUT_METHOD_OPTION_VALUE_XML "xml"
43: #define XDOC_OUTPUT_METHOD_OPTION_VALUE_HTML "html"
44: #define XDOC_OUTPUT_METHOD_OPTION_VALUE_TEXT "text"
45:
46: #define XDOC_OUTPUT_ENCODING_OPTION_NAME "encoding"
47:
48: #define XDOC_OUTPUT_DEFAULT_INDENT 4
49:
50: // class
51:
52: class MXdoc : public MXnode {
53: public: // VStateless_class
54: Value *create_new_value(Pool& pool) { return new(pool) VXdoc(pool); }
55:
56: public:
57: MXdoc(Pool& pool);
58:
59: public: // Methoded
60: bool used_directly() { return true; }
1.5 parser 61: void configure_admin(Request& r);
1.1 parser 62: };
63:
64: // methods
65:
66: class ParserStringXalanOutputStream: public XalanOutputStream {
67: public:
68:
69: explicit ParserStringXalanOutputStream(String& astring) : fstring(astring) {}
70:
71: protected: // XalanOutputStream
72:
73: virtual void writeData(const char *theBuffer, unsigned long theBufferLength) {
74: char *copy=(char *)fstring.malloc((size_t)theBufferLength);
75: memcpy(copy, theBuffer, (size_t)theBufferLength);
1.2 parser 76: fstring.APPEND_CLEAN(copy, (size_t)theBufferLength, "xdoc", 0);
1.1 parser 77: }
78:
79: virtual void doFlush() {}
80:
81: private:
82:
83: String& fstring;
84:
85: };
86:
1.9 ! parser 87: class XalanSourceTreeParserLiaison2: public XalanSourceTreeParserLiaison {
! 88: public:
! 89: XalanSourceTreeParserLiaison2(XalanSourceTreeDOMSupport& theSupport) : XalanSourceTreeParserLiaison(theSupport),
! 90: ferror_handler(new HandlerBase) {
! 91: setErrorHandler(ferror_handler); // disable stderr output
! 92: }
! 93: // virtual fatal?error!!
! 94:
! 95: ~XalanSourceTreeParserLiaison2() {
! 96: }
! 97: private:
! 98: ErrorHandler *ferror_handler;
! 99: };
! 100:
! 101: class XalanDefaultParsedSource2 : public XalanParsedSource
! 102: {
! 103: public:
! 104:
! 105: XalanDefaultParsedSource2(const XSLTInputSource& theInputSource);
! 106:
! 107: virtual
! 108: ~XalanDefaultParsedSource2();
! 109:
! 110: virtual XalanDocument*
! 111: getDocument() const;
! 112:
! 113: virtual XalanParsedSourceHelper*
! 114: createHelper() const;
! 115:
! 116: private:
! 117:
! 118: XalanSourceTreeDOMSupport m_domSupport;
! 119:
! 120: XalanSourceTreeParserLiaison2 m_parserLiaison;
! 121:
! 122: XalanSourceTreeDocument* const m_parsedSource;
! 123: };
! 124:
! 125: XalanDefaultParsedSource2::XalanDefaultParsedSource2(const XSLTInputSource& theInputSource):
! 126: XalanParsedSource(),
! 127: m_domSupport(),
! 128: m_parserLiaison(m_domSupport),
! 129: m_parsedSource(m_parserLiaison.mapDocument(m_parserLiaison.parseXMLStream(theInputSource)))
! 130: {
! 131: assert(m_parsedSource != 0);
! 132:
! 133: m_domSupport.setParserLiaison(&m_parserLiaison);
! 134: }
! 135:
! 136:
! 137:
! 138: XalanDefaultParsedSource2::~XalanDefaultParsedSource2()
! 139: {
! 140: }
! 141:
! 142:
! 143:
! 144: XalanDocument*
! 145: XalanDefaultParsedSource2::getDocument() const
! 146: {
! 147: return m_parsedSource;
! 148: }
! 149:
! 150:
! 151:
! 152: XalanParsedSourceHelper*
! 153: XalanDefaultParsedSource2::createHelper() const
! 154: {
! 155: return new XalanDefaultParsedSourceHelper(m_domSupport);
! 156: }
! 157:
! 158:
! 159:
! 160:
1.1 parser 161: static void create_optioned_listener(
162: const char *& content_type, const char *& charset, FormatterListener *& listener,
163: Pool& pool,
164: const String& method_name, MethodParams *params, int index, Writer& writer) {
165: // default encoding from pool
166: const String *scharset=&pool.get_charset();
167: const String *method=0;
168: XalanDOMString xalan_encoding;
169:
170: if(params->size()>index) {
171: Value& voptions=params->as_no_junction(index, "options must not be code");
172: if(voptions.is_defined()) {
173: if(Hash *options=voptions.get_hash()) {
174: // $.method[xml|html|text]
175: if(Value *vmethod=static_cast<Value *>(options->get(*new(pool)
176: String(pool, XDOC_OUTPUT_METHOD_OPTION_NAME))))
177: method=&vmethod->as_string();
178:
179: // $.encoding[windows-1251|...]
180: if(Value *vencoding=static_cast<Value *>(options->get(*new(pool)
181: String(pool, XDOC_OUTPUT_ENCODING_OPTION_NAME)))) {
182: scharset=&vencoding->as_string();
183: }
184: } else
185: PTHROW(0, 0,
186: &method_name,
187: "options must be hash");
188: }
189: }
190:
191: xalan_encoding.append(charset=scharset->cstr());
192: if(!method/*default='xml'*/ || *method == XDOC_OUTPUT_METHOD_OPTION_VALUE_XML) {
193: content_type="text/xml";
194: listener=new FormatterToXML(writer,
195: XalanDOMString(), // version
196: true, // doIndent
197: XDOC_OUTPUT_DEFAULT_INDENT, // indent
198: xalan_encoding // encoding
199: );
200: } else if(*method == XDOC_OUTPUT_METHOD_OPTION_VALUE_HTML) {
201: content_type="text/html";
202: listener=new FormatterToHTML(writer,
203: xalan_encoding, // encoding
204: XalanDOMString(), // mediaType
205: XalanDOMString(), // doctypeSystem; String to be printed at the top of the document
206: XalanDOMString(), // doctypePublic
207: true, // doIndent
208: XDOC_OUTPUT_DEFAULT_INDENT // indent
209: );
210: } else if(*method == XDOC_OUTPUT_METHOD_OPTION_VALUE_TEXT) {
211: content_type="text/plain";
212: listener=new FormatterToText(writer,
213: xalan_encoding // encoding
214: );
215: } else
216: PTHROW(0, 0,
217: method,
218: XDOC_OUTPUT_METHOD_OPTION_NAME " option is invalid; valid methods are: "
219: "'" XDOC_OUTPUT_METHOD_OPTION_VALUE_XML "', "
220: "'" XDOC_OUTPUT_METHOD_OPTION_VALUE_HTML "', "
221: "'" XDOC_OUTPUT_METHOD_OPTION_VALUE_TEXT "'");
222:
223: // never reached
224: }
225:
226: static void _save(Request& r, const String& method_name, MethodParams *params) {
227: Pool& pool=r.pool();
228: VXnode& vnode=*static_cast<VXnode *>(r.self);
229:
230: // filespec
231: const String& file_name=params->as_string(0, "file name must not be code");
232: const char *filespec=r.absolute(file_name).cstr(String::UL_FILE_SPEC);
233:
234: // node
235: XalanNode& node=vnode.get_node(pool, &method_name);
236:
237: try {
238: XalanFileOutputStream stream(XalanDOMString(filespec, strlen(filespec)));
239: XalanOutputStreamPrintWriter writer(stream);
240: const char *content_type, *charset;
241: FormatterListener *formatterListener;
242: create_optioned_listener(content_type, charset, formatterListener,
243: pool, method_name, params, 1, writer);
244: FormatterTreeWalker treeWalker(*formatterListener);
245: treeWalker.traverse(&node); // Walk that node and produce the XML...
246: } catch(const XSLException& e) {
247: r._throw(&method_name, e);
248: }
249: }
250:
251: static void _string(Request& r, const String& method_name, MethodParams *params) {
252: Pool& pool=r.pool();
253: VXnode& vnode=*static_cast<VXnode *>(r.self);
254:
255: // node
256: XalanNode& node=vnode.get_node(pool, &method_name);
257:
258: try {
259: String parserString=*new(pool) String(pool);
260: ParserStringXalanOutputStream stream(parserString);
261: XalanOutputStreamPrintWriter writer(stream);
262: const char *content_type, *charset;
263: FormatterListener *formatterListener;
264: create_optioned_listener(content_type, charset, formatterListener,
265: pool, method_name, params, 0, writer);
266: FormatterTreeWalker treeWalker(*formatterListener);
267: treeWalker.traverse(&node); // Walk that node and produce the XML...
268:
269: // write out result
270: r.write_no_lang(parserString);
271: } catch(const XSLException& e) {
272: r._throw(&method_name, e);
273: }
274: }
275:
276:
277: static void _file(Request& r, const String& method_name, MethodParams *params) {
278: Pool& pool=r.pool();
279: VXnode& vnode=*static_cast<VXnode *>(r.self);
280:
281: // node
282: XalanNode& node=vnode.get_node(pool, &method_name);
283:
284: try {
285: String& parserString=*new(pool) String(pool);
286: ParserStringXalanOutputStream stream(parserString);
287: XalanOutputStreamPrintWriter writer(stream);
288: const char *content_type, *charset;
289: FormatterListener *formatterListener;
290: create_optioned_listener(content_type, charset, formatterListener,
291: pool, method_name, params, 0, writer);
292: FormatterTreeWalker treeWalker(*formatterListener);
293: treeWalker.traverse(&node); // Walk that node and produce the XML...
294:
295: // write out result
296: VFile& vfile=*new(pool) VFile(pool);
297: const char *cstr=parserString.cstr();
298: String *scontent_type=new(pool) String(pool, content_type);
299: Value *vcontent_type;
300: if(charset) {
301: VHash *vhcontent_type=new(pool) VHash(pool);
302: vhcontent_type->hash().put(*value_name, new(pool) VString(*scontent_type));
303: String *scharset=new(pool) String(pool, charset);
304: vhcontent_type->hash().put(*new(pool) String(pool, "charset"), new(pool) VString(*scharset));
305: vcontent_type=vhcontent_type;
306: } else
307: vcontent_type=new(pool) VString(*scontent_type);
308: vfile.set(false/*tainted*/, cstr, strlen(cstr), 0/*file_name*/, vcontent_type);
309: r.write_no_lang(vfile);
310: } catch(const XSLException& e) {
311: r._throw(&method_name, e);
312: }
313: }
314:
315: static void _set(Request& r, const String& method_name, MethodParams *params) {
316: Pool& pool=r.pool();
1.5 parser 317: VXdoc& vdoc=*static_cast<VXdoc *>(r.self);
1.1 parser 318:
319: Value& vxml=params->as_junction(0, "xml must be code");
320: Temp_lang temp_lang(r, String::UL_XML);
321: const String& xml=r.process(vxml).as_string();
322:
323: std::istrstream stream(xml.cstr());
324: const XalanParsedSource* parsedSource;
1.9 ! parser 325: /* int error=vdoc.transformer().parseSource(&stream, parsedSource);
1.1 parser 326:
327: if(error)
328: PTHROW(0, 0,
329: &method_name,
1.5 parser 330: vdoc.transformer().getLastError());
1.9 ! parser 331: */
! 332:
! 333: int error;
! 334: CharVectorType m_errorMessage;
! 335: m_errorMessage.push_back(0);
! 336: try
! 337: {
! 338: parsedSource = new XalanDefaultParsedSource2(&stream);
! 339: error=0;
! 340:
! 341: //todo free parsedSource
! 342: }
! 343: catch (XSLException& e)
! 344: {
! 345: TranscodeToLocalCodePage(e.getMessage(), m_errorMessage, true);
! 346:
! 347: error = -1;
! 348: }
! 349: catch (SAXException& e)
! 350: {
! 351: TranscodeToLocalCodePage(e.getMessage(), m_errorMessage, true);
! 352:
! 353: error = -2;
! 354: }
! 355: catch (XMLException& e)
! 356: {
! 357: TranscodeToLocalCodePage(e.getMessage(), m_errorMessage, true);
! 358:
! 359: error = -3;
! 360: }
! 361: catch(const XalanDOMException& e)
! 362: {
! 363: XalanDOMString theMessage("XalanDOMException caught. The code is ");
! 364:
! 365: append(theMessage, LongToDOMString(long(e.getExceptionCode())));
! 366:
! 367: append(theMessage, XalanDOMString("."));
! 368:
! 369: TranscodeToLocalCodePage(theMessage, m_errorMessage, true);
! 370:
! 371: error = -3;
! 372: }
! 373:
! 374: if(error)
! 375: PTHROW(0, 0,
! 376: &method_name,
! 377: &m_errorMessage[0]);
1.1 parser 378:
379: // replace any previous parsed source
1.5 parser 380: vdoc.set_parsed_source(*parsedSource);
1.1 parser 381: }
382:
383: static void _load(Request& r, const String& method_name, MethodParams *params) {
384: Pool& pool=r.pool();
1.5 parser 385: VXdoc& vdoc=*static_cast<VXdoc *>(r.self);
1.1 parser 386:
387: // filespec
388: const String& file_name=params->as_string(0, "file name must not be code");
389: const char *filespec=r.absolute(file_name).cstr(String::UL_FILE_SPEC);
390:
391: const XalanParsedSource* parsedSource;
1.5 parser 392: int error=vdoc.transformer().parseSource(filespec, parsedSource);
1.1 parser 393:
394: if(error)
395: PTHROW(0, 0,
396: &file_name,
1.5 parser 397: vdoc.transformer().getLastError());
1.1 parser 398:
399: // replace any previous parsed source
1.5 parser 400: vdoc.set_parsed_source(*parsedSource);
1.1 parser 401: }
402:
403: static void add_xslt_param(const Hash::Key& aattribute, Hash::Val *ameaning,
404: void *info) {
405: XalanTransformer& transformer=*static_cast<XalanTransformer *>(info);
406: const char *attribute_cstr=aattribute.cstr();
407: const char *meaning_cstr=static_cast<Value *>(ameaning)->as_string().cstr();
408:
409: transformer.setStylesheetParam(
410: XalanDOMString(attribute_cstr),
411: XalanDOMString(meaning_cstr));
412: }
1.8 parser 413: static void _transform(Request& r, const String& method_name, MethodParams *params) {
1.1 parser 414: Pool& pool=r.pool();
1.5 parser 415: VXdoc& vdoc=*static_cast<VXdoc *>(r.self);
1.1 parser 416:
417: // params
418: if(params->size()>1) {
419: Value& vparams=params->as_no_junction(1, "transform parameters parameter must not be code");
420: if(vparams.is_defined())
421: if(Hash *params=vparams.get_hash())
1.5 parser 422: params->for_each(add_xslt_param, &vdoc.transformer());
1.1 parser 423: else
424: PTHROW(0, 0,
425: &method_name,
426: "transform parameters parameter must be hash");
427: }
428:
429: // source
1.5 parser 430: const XalanParsedSource &parsed_source=vdoc.get_parsed_source(pool, &method_name);
1.1 parser 431:
432: // stylesheet
433: const String& stylesheet_file_name=params->as_string(0, "file name must not be code");
434: const String& stylesheet_filespec=r.absolute(stylesheet_file_name);
435: //_asm int 3;
436: Stylesheet_connection& connection=XSLT_stylesheet_manager->get_connection(stylesheet_filespec);
437:
438: // target
1.5 parser 439: XalanDocument* target=vdoc.parser_liaison().createDocument();
1.1 parser 440: XSLTResultTarget domResultTarget(target);
441:
442: // transform
1.5 parser 443: int error=vdoc.transformer().transform(
1.1 parser 444: parsed_source,
1.6 parser 445: &connection.stylesheet(true/*nocache*/),
1.1 parser 446: domResultTarget);
447: connection.close();
448: if(error)
449: PTHROW(0, 0,
450: &stylesheet_file_name,
1.5 parser 451: vdoc.transformer().getLastError());
1.1 parser 452:
453: // write out result
454: VXdoc& result=*new(pool) VXdoc(pool);
455: result.set_document(*target);
456: r.write_no_lang(result);
457: }
458:
1.2 parser 459: static void _getElementById(Request& r, const String& method_name, MethodParams *params) {
460: Pool& pool=r.pool();
461: VXdoc& vdoc=*static_cast<VXdoc *>(r.self);
462:
463: // elementId
464: const char *elementId=params->as_string(0, "elementID must not be code").cstr(String::UL_AS_IS);
465:
466: if(XalanElement *element=
467: vdoc.get_document(pool, &method_name).getElementById(XalanDOMString(elementId))) {
468: // write out result
469: VXnode& result=*new(pool) VXnode(pool, element);
470: r.write_no_lang(result);
471: }
472: }
1.4 parser 473: /*
1.2 parser 474: static void _getElementsByTagName(Request& r, const String& method_name, MethodParams *params) {
475: Pool& pool=r.pool();
476: VXdoc& vdoc=*static_cast<VXdoc *>(r.self);
477:
478: // tagname
479: const char *tagname=params->as_string(0, "tagname must not be code").cstr(String::UL_AS_IS);
480:
481: VHash& result=*new(pool) VHash(pool);
482: if(const XalanNodeList *nodes=
483: vdoc.get_document(pool, &method_name).getElementsByTagName(XalanDOMString(tagname))) {
484: for(int i=0; i<nodes->getLength(); i++) {
485: String& skey=*new(pool) String(pool);
486: {
487: char *buf=(char *)pool.malloc(MAX_NUMBER);
488: snprintf(buf, MAX_NUMBER, "%d", i);
489: skey << buf;
490: }
491:
492: result.hash().put(skey, new(pool) VXnode(pool, nodes->item(i)));
493: }
494: }
495:
496: // write out result
497: r.write_no_lang(result);
498: }
499:
500: static void _getElementsByTagNameNS(Request& r, const String& method_name, MethodParams *params) {
501: Pool& pool=r.pool();
502: VXdoc& vdoc=*static_cast<VXdoc *>(r.self);
503:
504: // namespaceURI;localName
505: const char *namespaceURI=params->as_string(0, "namespaceURI must not be code").cstr(String::UL_AS_IS);
506: const char *localName=params->as_string(0, "localName must not be code").cstr(String::UL_AS_IS);
507:
508: VHash& result=*new(pool) VHash(pool);
509: if(const XalanNodeList *nodes=
510: vdoc.get_document(pool, &method_name).getElementsByTagNameNS(
511: XalanDOMString(namespaceURI), XalanDOMString(localName))) {
512: for(int i=0; i<nodes->getLength(); i++) {
513: String& skey=*new(pool) String(pool);
514: {
515: char *buf=(char *)pool.malloc(MAX_NUMBER);
516: snprintf(buf, MAX_NUMBER, "%d", i);
517: skey << buf;
518: }
519:
520: result.hash().put(skey, new(pool) VXnode(pool, nodes->item(i)));
521: }
522: }
523:
524: // write out result
525: r.write_no_lang(result);
526: }
1.4 parser 527: */
1.1 parser 528: // constructor
529:
530: MXdoc::MXdoc(Pool& apool) : MXnode(apool) {
531: set_name(*NEW String(pool(), XDOC_CLASS_NAME));
532:
1.2 parser 533: // ^xdoc.save[some.xml]
534: // ^xdoc.save[some.xml;options hash]
1.1 parser 535: add_native_method("save", Method::CT_DYNAMIC, _save, 1, 2);
536:
1.2 parser 537: // ^xdoc.string[] <doc/>
538: // ^xdoc.string[options hash] <doc/>
1.1 parser 539: add_native_method("string", Method::CT_DYNAMIC, _string, 0, 1);
540:
1.2 parser 541: // ^xdoc.file[] file with "<doc/>"
542: // ^xdoc.file[options hash] file with "<doc/>"
1.1 parser 543: add_native_method("file", Method::CT_DYNAMIC, _file, 0, 1);
544:
1.2 parser 545: // ^xdoc::set[<some>xml</some>]
1.1 parser 546: add_native_method("set", Method::CT_DYNAMIC, _set, 1, 1);
547:
1.2 parser 548: // ^xdoc::load[some.xml]
1.1 parser 549: add_native_method("load", Method::CT_DYNAMIC, _load, 1, 1);
550:
1.8 parser 551: // ^xdoc.transform[stylesheet file_name]
552: // ^xdoc.transform[stylesheet file_name;params hash]
553: add_native_method("transform", Method::CT_DYNAMIC, _transform, 1, 2);
1.2 parser 554:
555: // ^xdoc.getElementById[elementId]
556: add_native_method("getElementById", Method::CT_DYNAMIC, _getElementById, 1, 1);
1.4 parser 557: /*
1.3 parser 558: // ^xdoc.getElementsByTagName[tagname]
1.2 parser 559: add_native_method("getElementsByTagName", Method::CT_DYNAMIC, _getElementsByTagName, 1, 1);
560:
561: // ^xdoc.getElementsByTagNameNS[namespaceURI;localName] = array of nodes
562: add_native_method("getElementsByTagNameNS", Method::CT_DYNAMIC, _getElementsByTagNameNS, 2, 2);
1.4 parser 563: */
1.1 parser 564: }
1.5 parser 565:
566: void MXdoc::configure_admin(Request& r) {
567: }
568:
1.1 parser 569: // global variable
570:
571: Methoded *Xdoc_class;
572:
573: // creator
574:
575: #endif
576:
577: Methoded *MXdoc_create(Pool& pool) {
578: return
579: #ifdef XML
580: Xdoc_class=new(pool) MXdoc(pool);
581: #else
582: 0
583: #endif
584: ;
585: }
E-mail: