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