1 /* Copyright (C) 2000-2006 Thomas Bopp, Thorsten Hampel, Ludger Merkens
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 * $Id: DocXSL.pike,v 1.1 2008/03/31 13:39:57 exodusd Exp $
19 inherit "/base/xml_data";
20 inherit "/base/xml_parser";
21 inherit "/classes/Document";
22 inherit Events.Listener;
25 #include <attributes.h>
29 #include <exception.h>
31 //! This class keep XSL Stylesheets and is able to do XSLT with libxslt
32 class DocXSL : public xml_data,xml_parser,Document{
41 //#define DOCXSL_DEBUG
44 #define DEBUG_DOCXSL(s, args...) werror(s+"\n", args)
51 mapping mDepend = ([ ]);
52 mapping mLang = ([ ]);
53 bool xmlIsLoad = false;
56 mapping mStylesheets = ([ ]); // all stylesheet objects
57 object oDescriptionXML;
60 Thread.Mutex xmlMutex = Thread.Mutex();
63 mapping mAttrConv = ([
64 101 : "OBJ_OWNER", 102 : "OBJ_NAME", 104 : "OBJ_DESC",
65 105 : "OBJ_ICON", 111 : "OBJ_KEYWORDS", 112 : "OBJ_COMMAND_MAP",
66 113 : "OBJ_POSITION_X", 114 : "OBJ_POSITION_Y", 115 : "OBJ_POSITION_Z",
67 116 : "OBJ_LAST_CHANGED", 119 : "OBJ_CREATION_TIME", "url" : "OBJ_URL",
68 "obj:link_icon" : "OBJ_LINK_ICON", "obj_script" : "OBJ_SCRIPT",
69 "obj_annotations_changed" : "OBJ_ANNOTATIONS_CHANGED",
70 207 : "DOC_TYPE", 208 : "DOC_MIME_TYPE", 213 :
72 214 : "DOC_LAST_MODIFIED", 215 : "DOC_LAST_ACCESSED",
73 216 : "DOC_EXTERN_URL", 217 : "DOC_TIMES_READ",
74 218 : "DOC_IMAGE_ROTATION", 219 : "DOC_IMAGE_THUMBNAIL",
75 220 : "DOC_IMAGE_SIZEX", 221 : "DOC_IMAGE_SIZEY",
76 300 : "CONT_SIZE_X", 301 : "CONT_SIZE_Y", 302 : "CONT_SIZE_Z",
77 303 : "CONT_EXCHANGE_LINKS", "cont:monitor" : "CONT_MONITOR",
78 "cont_last_modified" : "CONT_LAST_MODIFIED",
79 500 : "GROUP_MEMBERSHIP_REQS", 501 : "GROUP_EXITS",
80 502 : "GROUP_MAXSIZE", 503 : "GROUP_MSG_ACCEPT",
81 504 : "GROUP_MAXPENDING", 611 : "USER_ADRESS", 612 :
83 613 : "USER_MAILBOX", 614 : "USER_WORKROOM", 615 :
85 616 : "USER_EMAIL", 617 : "USER_UMASK", 618 : "USER_MODE",
86 619 : "USER_MODE_MSG", 620 : "USER_LOGOUT_PLACE",
87 621 : "USER_TRASHBIN", 622 : "USER_BOOKMARKROOM",
88 623 : "USER_FORWARD_MSG", 624 : "USER_IRC_PASSWORD",
89 "user_firstname" : "USER_FIRSTNAME", "user_language" :
91 "user_selection" : "USER_SELECTION",
92 "user_favorites" : "USER_FAVOURITES", 700 : "DRAWING_TYPE",
93 701 : "DRAWING_WIDTH", 702 : "DRAWING_HEIGHT", 703 :
95 704 : "DRAWING_THICKNESS", 705 : "DRAWING_FILLED",
96 800 : "GROUP_WORKROOM", 801 : "GROUP_EXCLUSIVE_SUBGROUPS",
97 1000 : "LAB_TUTOR", 1001 : "LAB_SIZE", 1002 : "LAB_ROOM",
98 1003 : "LAB_APPTIME", 1100 : "MAIL_MIMEHEADERS",
99 1101 : "MAIL_IMAPFLAGS"
102 mapping mUpdates = ([ ]);
104 class UpdateListener {
109 void create(object obj, object _this) {
110 ::create(EVENT_UPLOAD, PHASE_NOTIFY, obj, 0);
112 obj->listen_event(this_object());
114 void notify(int event, mixed args) {
115 if ( zero_type(::get_object()) ) {
116 destruct(this_object());
119 if ( _Server->query_config("xsl_disable_auto_reload") ) {
120 //MESSAGE("XSL: no auto reload (server config) ...");
124 __obj->load_xml_structure(); // reload
125 __obj->inc_stylesheet_changed(); // refresh xsl
133 return "UpdateListener("+
134 (objectp(__obj)?__obj->get_identifier():"null")+")";
136 string _sprintf() { return describe(); }
143 * load the document - initialize the xslt.Stylesheet() object.
144 * This is called when the XSL stylesheet is loaded.
150 XML = _Server->get_module("Converter:XML");
151 if ( !do_query_attribute(OBJ_VERSIONOF) )
152 load_xml_structure();
159 * Add a dependant stylesheet and notify it when the content
160 * of this stylesheet changed.
162 * @param object o - the dependant stylesheet
164 void add_depend(object o)
170 void xsl_add_depend(object obj)
172 array listenings = do_query_attribute("DOCXSL_DEPENDS") || ({ });
173 if ( search(listenings, obj) >= 0 )
175 listenings += ({ obj });
176 do_set_attribute("DOCXSL_DEPENDS", listenings);
182 void xsl_listen_depends()
184 array listenings = do_query_attribute("DOCXSL_DEPENDS") || ({ });
185 foreach(listenings, object l) {
186 if ( !objectp(mUpdates[l]) )
194 * callback function to find a stylesheet.
196 * @param string uri - the uri to locate the stylesheet
197 * @return the stylesheet content or zero.
201 find_stylesheet(string uri, string language)
207 LOG("find_stylesheet("+uri+","+language+")");
209 if ( uri[0] == '/' ) {
210 obj = _FILEPATH->path_to_object(uri);
211 if ( objectp(obj) ) {
212 string contstr = obj->get_language_content(language);
215 FATAL("Failed to find Stylesheet: "+ uri +" !");
220 while ( (i=search(uri, "../")) == 0 && objectp(cont) ) {
221 cont = cont->get_environment();
224 LOG("Looking up in " + _FILEPATH->object_to_filename(cont));
225 obj = _FILEPATH->resolve_path(cont, uri);
227 if ( objectp(obj) ) {
228 return obj->get_language_content(language);
236 int match_stylesheet(string uri)
238 if ( search(uri, "steam:") == 0 )
246 object open_stylesheet(string uri)
248 sscanf(uri, "steam:/%s", uri);
249 object obj = _FILEPATH->path_to_object(uri);
251 if ( !objectp(obj) ) {
252 FATAL("Stylesheet " + uri + " not found !");
255 DEBUG_DOCXSL("open_stylesheet("+uri+") - " + (objectp(obj)?"success":"failed"));
263 read_stylesheet(object|string obj, string language, int position)
265 if ( stringp(obj) ) {
266 sscanf(obj, "steam://%s", obj);
267 obj = find_object(obj);
270 if ( objectp(obj) ) {
272 DEBUG_DOCXSL("read_stylesheet(language="+language+")");
273 string contstr = obj->get_language_content(language);
274 DEBUG_DOCXSL("length="+strlen(contstr) + " of " + obj->get_object_id());
277 DEBUG_DOCXSL("No stylesheet given for reading...");
285 close_stylesheet(object obj)
294 foreach(values(mStylesheets), object stylesheet)
295 destruct(stylesheet);
297 mStylesheets = ([ ]);
298 foreach( indices(mDepend), object o ) {
300 o->inc_stylesheet_changed();
306 void inc_stylesheet_changed()
308 DEBUG_DOCXSL("Reloading XSL Stylesheet: "+get_identifier());
314 * Unserialize a myobject tag from the xml description file.
316 * @param string data - myobject data.
317 * @return the corresponding object
320 object unserialize_myobject(string data)
324 return (object)find_object(id);
327 if ( sscanf(data, "%s:%s", prefix, val) == 2 ) {
330 return MODULE_GROUPS->lookup(val);
333 object oOrb = _FILEPATH->path_to_object(val);
334 if (objectp(oOrb) && oOrb->get_object_class() & CLASS_DOCLPC &&
335 functionp(oOrb->provide_instance))
337 oOrb = oOrb->provide_instance();
338 catch{ oOrb->get_identifier(); };
342 return get_module("filepath:url")->path_to_object(val);
351 return XML->THIS->ENV;
356 return XML->THIS_USER;
374 return MODULE_GROUPS->lookup("sTeam");
377 return this_object();
386 return MODULE_GROUPS->lookup("admin");
389 return _Server->get_module(data);
392 return steam_error("Failed to serialize object:"+data);
397 mapping get_default_map(string data)
413 return XML->userInvXML;
416 return XML->containerXML;
421 FATAL("Warning: Default map of " + data + " not found in %s",
426 mixed unserialize_var(mixed name, mixed defval)
428 return XML->get_var(name, defval);
438 mixed unserialize(NodeXML n)
441 if ( n->name == "myobject" || n->name == "o" ) {
442 return unserialize_myobject(n->data);
444 else if ( n->name == "var" ) {
445 object datanode = n->get_node("def");
446 if ( sizeof(datanode->children) ) {
447 FATAL("datanode with children found:" +
448 datanode->children[0]->data+"\n");
449 return unserialize_var(
450 n->get_node("name")->data,
451 unserialize(datanode->children[0]));
454 return unserialize_var(
455 n->get_node("name")->data,
456 n->get_node("def")->data);
458 else if ( n->name == "object" ) {
459 object node = n->get_node("path");
460 if ( objectp(node) ) {
461 if ( node->name="group" )
462 return MODULE_GROUPS->lookup(node->data);
463 else if ( node->name = "path" )
464 return get_module("filepath:tree")->path_to_object(node->data);
467 else if ( n->name == "maps" ) {
469 foreach(n->children, NodeXML children) {
470 mapping m = get_default_map(children->data);
475 else if ( n->name == "function" ) {
476 NodeXML obj = n->get_node("object");
477 NodeXML f = n->get_node("name");
478 NodeXML id = n->get_node("id");
479 switch ( obj->data ) {
481 func = (function)this_object()[f->data];
485 func = [function](m[f->data]);
488 func = [function](_Server[f->data]);
492 o = _Server->get_module(obj->data);
494 FATAL("Module not found: " + obj->data);
498 func = o->find_function(f->data);
499 if (!functionp(func))
500 FATAL("Failed to find function " + f->data + " in %O", o);
503 FATAL("Failed to deserialize function: " + f->data +
504 " inside " + master()->describe_object(o) + "\n"+
505 err[0] + "\n" + sprintf("%O", err[1]));
510 if ( !functionp(func) )
511 LOG("unserialize_function: no functionp :"+
512 sprintf("%O\n",func));
515 return ::unserialize(n);
525 string compose_scalar(mixed val)
527 if ( objectp(val) ) {
528 if ( val == XML->THIS )
529 return "<myobject>THIS</myobject>";
530 else if ( val == XML->CONV )
531 return "<myobject>CONV</myobject>";
532 else if ( XML->THIS_USER == val )
533 return "<myobject>THIS_USER</myobject>";
534 else if ( _Server == val )
535 return "<myobject>SERVER</myobject>";
536 else if ( XML->LAST == val )
537 return "<myobject>LAST</myobject>";
538 else if ( XML->ACTIVE == val )
539 return "<myobject>ACTIVE</myobject>";
540 else if ( XML->ENTRY == val )
541 return "<myobject>ENTRY</myobject>";
542 else if ( XML->XSL == val )
543 return "<myobject>XSL</myobject>";
545 return ::compose_scalar(val);
555 mixed compose(mixed m)
557 if ( functionp(m) ) {
558 object o = function_object(m);
560 LOG("function without object:" + function_name(m));
563 if ( o == this_object())
564 return "<function><object>local</object><name>"+function_name(m)+
565 "</name></function>";
566 else if ( o == master() )
567 return "<function><object>master</object>"+
568 "<name>"+function_name(m) + "</name></function>";
569 else if ( o == _Server )
570 return "<function><object>server</object>"+
571 "<name>"+function_name(m) + "</name></function>";
573 return "<function><id>"+o->get_object_id()+
574 "</id><object>"+o->get_identifier()+"</object>"+
575 "<name>"+function_name(m) + "</name></function>";
580 object find_xml(void|object xml)
586 if ( objectp(oEnvironment) ) {
587 xml = oEnvironment->get_object_byname(get_identifier()+".xml");
588 sscanf(get_identifier(), "%s.%*s", name);
590 if ( !objectp(xml) ) {
591 xml = oEnvironment->get_object_byname(name+".xgl");
595 xml = do_query_attribute(DOC_XSL_XML);
597 // fall back to public Stylesheet, if available
598 if ( !objectp(xml) || xml->status() < 0 || xml->status() == PSTAT_DELETED ) {
599 xml = OBJ("/stylesheets/public.xsl.xml");
604 array load_imports(object n)
608 nodes = n->get_nodes("language");
612 foreach(nodes, object node) {
613 array imports = ({ });
615 if ( stringp(node->attributes->auto) ) {
616 object languageCont = OBJ("/languages");
617 if ( objectp(languageCont) ) {
618 array languageNodes = ({ });
619 foreach( languageCont->get_inventory_by_class(CLASS_DOCXML), object langXML)
621 NodeXML langnode = xmlCache.parse(langXML);
622 imports += langnode->get_nodes("import");
623 languageNodes += ({ langnode });
625 node->replace_node( languageNodes );
629 imports = node->get_nodes("import");
631 foreach(imports, object imp) {
633 object importNodes = parse_import(imp->attributes->file);
634 if ( !objectp(importNodes) )
636 imp->replace_node(importNodes,
637 imp->attributes->xpath);
640 if ( !stringp(imp->attributes->file) )
641 FATAL("Importing language: "+
642 "Missing file attribute on %s tag !",
645 FATAL("Failed to import file: %s, %O\%O",
646 imp->attributes->file, e[0], e[1]);
655 int in_backtrace(object obj)
657 if ( !objectp(obj) || !functionp(obj->get_object) ||
658 !objectp(obj->get_object()) )
661 foreach( backtrace(), mixed preceed ) {
662 if ( function_object(preceed[2]) == obj->get_object() )
671 * Load the related xgl (or xsl.xml) document
674 void load_xml_structure(void|object xml)
676 if ( in_backtrace(get_module("tar")) ) {
677 call(load_xml_structure, 1);
681 return; // do not load xml for old versions
683 // factories must be loaded
684 if ( !objectp(get_factory(CLASS_OBJECT)) ) {
685 call(load_xml_structure, 1);
689 object xmlLock = xmlMutex->trylock();
690 if ( !objectp(xmlLock) )
691 steam_error("Failed to obtain xml-lock in %O", get_identifier());
693 mixed xmlErr = catch {
695 if ( objectp(xml) ) {
698 NodeXML n = parse_data(xml->get_content());
699 array nodes = load_imports(n);
700 mLang = read_languages(nodes);
702 object xmlscript = do_query_attribute(DOC_XSL_PIKE);
705 throw( ({ "Root node '<structure>' not found in "+
706 "XML description file !", backtrace() }) );
708 if ( n->name == "structure" ) {
709 if ( (stringp(n->attributes->generate) &&
710 n->attributes->generate == "pike") ||
711 stringp(n->get_pi()["steam"]) )
713 object oldeuid = geteuid();
714 seteuid(get_creator());
719 if ( objectp(xmlscript) )
721 do_set_attribute(DOC_XSL_PIKE);
727 if ( CALLER != this_object() ) {
729 FATAL("No description file ("+get_identifier()+".xml) found for Stylesheet !");
733 xsl_listen_depends();
738 FATAL("Failed to load xml structure for %s\n%O",
739 _FILEPATH->object_to_filename(this_object()),
742 if ( CALLER != this_object() ) {
751 string read_import(string fname)
753 object f = _FILEPATH->path_to_object(fname);
758 return f->get_content();
764 object parse_import(string fname)
766 object f = _FILEPATH->path_to_object(fname);
771 return xmlCache.parse(f);
776 int check_xgl_consistency(object xmlscript, object xmlObj)
778 if ( objectp(xmlscript) ) {
779 object script_xml = xmlscript->query_attribute(DOCLPC_XGL);
780 if ( objectp(script_xml) && do_query_attribute(DOC_XSL_XML) != script_xml )
782 FATAL("DocXSL: mismatched Pike-Script and XGL File !");
783 do_set_attribute(DOC_XSL_XML);
784 xmlObj->set_attribute(DOC_LAST_MODIFIED, time());
793 void hook_xml(object xmlObj, void|object rootNode)
795 object xmlscript = do_query_attribute(DOC_XSL_PIKE);
796 if (objectp(xmlscript) && xmlscript->status() < 0)
799 check_xgl_consistency(xmlscript, xmlObj);
800 if ( xmlObj == OBJ("/stylesheets/public.xsl.xml") ) {
801 object oxgl = do_query_attribute(DOC_XSL_XML);
806 if (objectp(xmlscript))
807 tss = xmlscript->query_attribute(DOCLPC_INSTANCETIME);
808 int tsc = xmlObj->query_attribute(DOC_LAST_MODIFIED);
810 DEBUG_DOCXSL("Timestamp test when hooking XML: (tss=%d, tsc=%d)", tss, tsc);
811 // also see if XGL file has not changed !
813 if ( tss > tsc && do_query_attribute(DOC_XSL_XML) == xmlObj )
816 string pikecode = XMLCodegen.codegen(xmlObj, read_import);
817 set_attribute(DOC_XSL_XML, xmlObj);
819 DEBUG_DOCXSL("Updating Pike XML Generation ...");
820 string scriptname = get_object_id() + ".pike";
821 if ( !objectp(xmlscript) )
822 xmlscript = get_factory(CLASS_DOCUMENT)->execute(([ "name": scriptname,]));
825 do_set_attribute(DOC_XSL_PIKE, xmlscript);
826 xmlscript->set_attribute(DOCLPC_XGL, xmlObj);
828 if ( !check_xgl_consistency(xmlscript, xmlObj) )
829 steam_error("DocXSL: consistency check failed .... !");
831 err = catch(xmlscript->set_content(pikecode));
832 if ( arrayp(xmlscript->get_errors()) && sizeof(xmlscript->get_errors()) > 0 ) {
833 FATAL("Errors in xml Script: %O", xmlscript->get_errors());
835 catch(xmlscript->sanction_object(GROUP("everyone"),SANCTION_READ|SANCTION_EXECUTE));
837 FATAL("Failed to hook xml content: %s", err[0]);
838 xmlscript->provide_instance(); // should create an instance when loaded
844 * Get the xml structure as a mapping.
846 * @return the xml structure mapping
848 mapping get_xml_structure()
850 return copy_value(mXML);
856 * Resolves the show function of the xml tag definition and returns a
857 * mapping or function with corresponding informations.
859 * @param NodeXML n - the node to convert
860 * @return mapping or function of node information
862 function|mapping xmlTagShowFunc(NodeXML n)
866 NodeXML f = n->get_node("f");
868 NodeXML m = n->get_node("map");
870 m = n->get_node("structure");
875 if ( m->attributes->name )
876 res["name"] = m->attributes->name;
878 foreach(m->children, object tag) {
879 if ( tag->name == "tag" ) {
880 res[tag->attributes->name] += xmlTag(tag);
882 else if ( tag->name == "def" ) {
883 mapping def = get_default_map(tag->data);
884 if ( mappingp(def) ) {
894 NodeXML na = f->get_node("n");
895 NodeXML o = f->get_node("o");
897 THROW("Function tag (f) has no sub tag 'n' !", E_ERROR);
902 obj = unserialize_myobject(o->data);
904 steam_error("Failed to find object " + o->data);
910 steam_user_error("Missing 'n' Node inside <f> to specify function!");
911 func = [function]obj->find_function(na->data);
912 if (!functionp(func))
913 FATAL("Failed to find function " + na->data + " in %O", obj);
916 FATAL("Failed to deserialize function in: " + f->dump() +
923 * Convert possible calls to Attribute functions to new string format
924 * (previously numbers where used.
926 * @param string fname - name of the function to be called.
927 * @param array params - the params to convert
928 * @return new parameters
931 array attribute_conversion(string fname, array params)
933 if ( fname == "query_attribute" ) {
934 for ( int i = sizeof(params) - 1; i >= 0; i-- ) {
935 if ( stringp(mAttrConv[params[i]]) ) {
936 params[i] = mAttrConv[params[i]];
946 * Resolve the xml tag call function definition. Which function to call
949 * @param NodeXML n - the Node <tag>
950 * @return corresponding information array with structure used by converter
952 array xmlTagCallFunc(NodeXML n)
957 return ({ XML->THIS, "null", ({ }), 0 });
959 NodeXML f = n->get_node("n");
960 NodeXML o = n->get_node("o");
961 NodeXML p = n->get_node("p");
966 THROW("No Node n (function-name) found at function tag", E_ERROR);
971 obj = unserialize_myobject(o->data);
973 p->data = String.trim_whites(p->data - "\n");
974 if ( stringp(p->data) && strlen(p->data) > 0 )
975 steam_error("Found data in param tag - all params need to be "+
976 "in type tags like <int>42</int>.\n"+
977 "Context: "+n->get_xml()+"\nOffending:\n"+p->data);
978 params = xmlArray(p);
979 params = attribute_conversion(f->data, params);
981 if ( !arrayp(params) )
984 res = ({ obj, f->data, params, 0 });
989 private array xmlTag(NodeXML n)
992 object call = n->get_node("call/f");
993 res = xmlTagCallFunc(call);
994 res[3] = xmlTagShowFunc(n->get_node("show"));
1001 private mapping xmlTags(NodeXML n)
1003 mapping res = ([ ]);
1004 foreach(n->children, object node) {
1005 if ( node->name == "class" ) {
1007 string type = node->attributes->type;
1010 object f = _Server->get_factory(type);
1012 t = f->get_class_id();
1014 steam_error("Unable to find factory for " + type);
1017 steam_error("Fatal error loading xml structure: " +
1018 "Unable to identify class-id for '" + type + "'.");
1021 foreach(node->get_nodes("tag"), object tag) {
1022 if ( !objectp(tag->get_node("call") ) )
1023 continue; // ignore nodes with call
1024 res[t][tag->attributes->name] = xmlTag(tag);
1028 if ( n->attributes->name )
1029 res["name"] = n->attributes->name;
1037 mapping read_languages(array(NodeXML) nodes, void|object xml)
1039 mapping res = ([ ]);
1041 if ( !arrayp(nodes) )
1044 foreach(nodes, object node) {
1045 if ( node->name == "language" ) {
1046 res[node->attributes->name] = ([ ]);
1047 foreach(node->get_nodes("term"), object term) {
1048 res[node->attributes->name]["{"+term->attributes->name+"}"]=term->get_data();
1061 // successfull upload...
1062 ::content_finished();
1069 * Get the content of this object with replacements for the language.
1070 * This means that templates like {TEMPLATE_NAME} are replaced with
1071 * the corresponding entry in the xml file. If the language is not
1072 * defined then english is used as default language.
1074 * @param void|string language - the language
1075 * @return the stylesheet.
1078 string get_language_content(void|string language)
1081 if ( stringp(language) ) {
1082 string str = ::get_content();
1084 if ( mappingp(mLang[language]) ) {
1085 mapping m = mLang[language];
1086 content = replace(str, indices(m), values(m));
1088 else if ( mappingp(mLang->english) ) {
1089 content = replace(str, indices(mLang->english),values(mLang->english));
1092 //FATAL("No Languages initialized for %s", get_identifier());
1098 return ::get_content();
1103 * Get the xslt.Stylesheet() object.
1105 * @return the stylesheet.
1107 object get_stylesheet(string|void language)
1111 object lock = xmlMutex->lock();
1114 steam_error("DocXSL: Cannot retrieve data from uninitialized Stylesheet!");
1117 if ( !stringp(language) )
1118 language = "english";
1120 if ( !objectp(mStylesheets[language]) ) {
1121 // now I got some (the real one, but it needs internationalization)
1125 string xsl_code = get_language_content(language);
1126 xsl_code = replace( xsl_code, " ", " " );
1128 stylesheet = xslt.Stylesheet();
1129 mStylesheets[language] = stylesheet;
1131 stylesheet->set_include_callbacks(match_stylesheet,
1135 stylesheet->set_language(language);
1136 stylesheet->set_content(xsl_code);
1139 destruct(stylesheet);
1140 mStylesheets[language] = 0;
1141 err[0] = "Error Parsing " + get_identifier() + "\n" + err[0];
1148 if ( objectp(mStylesheets[language]) ) {
1149 return mStylesheets[language];
1151 return mStylesheets["english"];
1156 object xsl = get_stylesheet();
1158 return xsl->get_method();
1162 string get_encoding()
1164 object xsl = get_stylesheet();
1166 return xsl->get_encoding();
1172 return ({ "content", "attributes", "access", "annotations" });
1175 bool check_swap() { return false; } // do not swap out stylesheets
1176 int get_object_class() { return ::get_object_class() | CLASS_DOCXSL; }
1177 string get_class() { return "DocXSL"; }
1181 // check xsl.xml here...
1182 MESSAGE("* Testing DocXSL functionality and libxslt ...");
1183 MESSAGE("Creating test container...");
1184 object testcont = OBJ("/home/steam/__xsltestcont");
1185 if ( !objectp(testcont) ) {
1186 testcont=get_factory(CLASS_CONTAINER)->execute( (["name":"__xsltestcont"]) );
1187 testcont->move(OBJ("/home/steam"));
1189 foreach(testcont->get_inventory(), object inv) {
1195 MESSAGE("Creating language file...");
1196 object languages = get_factory(CLASS_DOCUMENT)->execute( (["name":"terms.xml",]) );
1197 MESSAGE("Language file is %O", languages);
1198 languages->set_content("<?xml version='1.0' encoding='utf-8'?>\n<language><term name='TERM1'>term_1</term></language>\n");
1199 languages->move(testcont);
1201 string pathname = _FILEPATH->object_to_filename(languages);
1203 MESSAGE("Creating XGL File...");
1204 object xgl = get_factory(CLASS_DOCUMENT)->execute( (["name": "test.xgl", ]) );
1205 xgl->set_content("<?xml version='1.0' encoding='utf-8'?>\n<structure generate='pike'>\n<class type='Object'>\n<tag name='test'><call><function name='get_identifier' /></call><show><function name='show' /></show></tag></class><language name='english'><import file='"+pathname+"' xpath='term' /></language>\n</structure>\n");
1207 xgl->move(testcont);
1208 MESSAGE("Testing xsl...");
1209 set_content("<?xml version='1.0' encoding='utf-8'?>\n<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='1.0'>\n<xsl:output method='html' encoding='utf-8' />\n<xsl:template match='Object/test'>{TERM1}: testing</xsl:template>\n</xsl:stylesheet>");
1210 if (find_xml()!=xgl)
1211 steam_error("find_xml() does not return proper XGL file !");
1212 load_xml_structure(xgl);
1214 object pikescript = do_query_attribute(DOC_XSL_PIKE);
1215 if ( !objectp(pikescript) )
1216 steam_error("Generation of Pike-Script failed !");
1218 MESSAGE("Looking for UpdateListener ...");
1219 if ( !objectp(mUpdates[xgl]) )
1220 steam_error("No Update Listener for XGL ...");
1221 if ( !objectp(mUpdates[languages]) ) {
1222 MESSAGE("Dumping Update Listeners:\n%O", indices(mUpdates));
1223 steam_error("No Update Listener for Language Term File (%O) ...", languages);
1225 call(test_more, 1, pikescript, xgl, languages, testcont, "", 0);
1228 void test_more(object pikescript, object xgl, object languages, object testcont, string xml, int test)
1230 if ( pikescript->status() != PSTAT_DISK ) {
1232 call(test_more, 5, pikescript, xgl, languages, testcont, xml, test);
1237 MESSAGE("Testing xml generation !");
1238 mapping params = ([ "this_user": USER("root")->get_object_id(), ]);
1239 MESSAGE("DOC_XSL_PIKE=%O", do_query_attribute(DOC_XSL_PIKE));
1240 // xgl file controls xml generatoin - should be simple xml
1241 MESSAGE("XML Generated: \n%s---", xml);
1242 if ( search(xml, "XGL File: "+_FILEPATH->object_to_filename(xgl)) == -1 )
1243 steam_error("XGL Test: Used wrong xgl file for XML Generation !");
1244 MESSAGE("OUTPUT = %s", result);
1245 call(test_more, 2, pikescript, xgl, languages, testcont, xml, 1);
1248 MESSAGE("Testing update of depend...");
1249 languages->set_content("<?xml version='1.0' encoding='utf-8'?>\n<language><term name='TERM1'>modified</term></language>\n");
1250 if ( search(result, "modified") == -1 )
1251 steam_error("Language File Update did not update Term Definition in %O !"+
1252 "\nDump: %s", languages, result);
1253 languages->delete();