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