libxslt_processor.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872
  1. #include "jliball.hpp"
  2. #include <string.h>
  3. #include <libxml/xmlmemory.h>
  4. #include <libxml/parserInternals.h>
  5. #include <libxml/debugXML.h>
  6. #include <libxml/HTMLtree.h>
  7. #include <libxml/xmlIO.h>
  8. #include <libxml/xinclude.h>
  9. #include <libxml/catalog.h>
  10. #include <libxml/xpathInternals.h>
  11. #include <libxslt/xslt.h>
  12. #include <libxslt/xsltInternals.h>
  13. #include <libxslt/transform.h>
  14. #include <libxslt/documents.h>
  15. #include <libxslt/xsltutils.h>
  16. #include <libxslt/extensions.h>
  17. #include <libxslt/variables.h>
  18. #include <libexslt/exslt.h>
  19. #ifdef _WIN32
  20. #undef new
  21. #undef delete
  22. #endif
  23. #include "xslprocessor.hpp"
  24. #include "xslcache.hpp"
  25. #include "xmlerror.hpp"
  26. extern int xmlLoadExtDtdDefaultValue;
  27. xsltDocLoaderFunc originalLibXsltIncludeHandler = NULL;
  28. xmlDocPtr libXsltIncludeHandler(const xmlChar * URI, xmlDictPtr dict, int options, IIncludeHandler* handler, xsltLoadType type);
  29. xmlDocPtr globalLibXsltIncludeHandler(const xmlChar * URI, xmlDictPtr dict, int options, void *ctx, xsltLoadType type);
  30. void libxsltCustomMessageHandler(StringBuffer& out, const char* in, IXslTransform* transform);
  31. class CLibXsltSource : public CInterface, implements IXslBuffer
  32. {
  33. public:
  34. IMPLEMENT_IINTERFACE;
  35. CLibXsltSource(const char* fname) : filename(fname), cacheId(fname), compiledXslt(NULL)
  36. {
  37. srcType = IO_TYPE_FILE;
  38. }
  39. CLibXsltSource(IIncludeHandler *handler, const char* rootpath, const char *_cacheId) : cacheId(_cacheId), compiledXslt(NULL), filename(rootpath)
  40. {
  41. srcType = IO_TYPE_BUFFER;
  42. bool pathOnly=false;
  43. MemoryBuffer mb;
  44. if (!handler->getInclude(rootpath, mb, pathOnly) || pathOnly || !mb.length())
  45. throw MakeStringException(XSLERR_InvalidSource, "Failed to load XSLT resource path %s\n", rootpath);
  46. text.set(mb.toByteArray(), mb.length());
  47. StringBuffer s("file://");
  48. if (*rootpath!='/')
  49. s.append('/');
  50. filename.set(s.append(rootpath).str());
  51. }
  52. CLibXsltSource(const char* s, int len, const char *_cacheId) : cacheId(_cacheId), compiledXslt(NULL)
  53. {
  54. srcType = IO_TYPE_BUFFER;
  55. text.set(s, len);
  56. filename.set("buffer.xslt");
  57. }
  58. virtual ~CLibXsltSource()
  59. {
  60. if (compiledXslt)
  61. xsltFreeStylesheet(compiledXslt);
  62. }
  63. virtual void compile();
  64. virtual bool isCompiled() const {return compiledXslt!=NULL;}
  65. virtual IO_Type getType() {return srcType;}
  66. virtual const char* getFileName(){return filename.get();}
  67. virtual char* getBuf(){return (char*)text.get();}
  68. virtual int getLen(){return text.length();}
  69. virtual StringArray& getIncludes(){return includes;}
  70. virtual const char *getCacheId(){return cacheId.get();}
  71. void setIncludeHandler(IIncludeHandler* handler){includeHandler.set(handler);}
  72. xsltStylesheetPtr getCompiledXslt();
  73. xsltStylesheetPtr parseXsltFile();
  74. public:
  75. IO_Type srcType;
  76. StringAttr filename;
  77. StringAttr cacheId;
  78. StringAttr text;
  79. Owned<IIncludeHandler> includeHandler;
  80. StringArray includes;
  81. xsltStylesheetPtr compiledXslt;
  82. };
  83. xsltStylesheetPtr CLibXsltSource::getCompiledXslt()
  84. {
  85. if (compiledXslt)
  86. return compiledXslt;
  87. IXslCache* xslcache = getXslCache();
  88. if (xslcache)
  89. {
  90. IXslBuffer* xslbuffer = xslcache->getCompiledXsl(this, false);
  91. if (xslbuffer)
  92. return ((CLibXsltSource*)xslbuffer)->compiledXslt;
  93. }
  94. compile();
  95. return compiledXslt;
  96. }
  97. xsltStylesheetPtr CLibXsltSource::parseXsltFile()
  98. {
  99. if (filename.isEmpty())
  100. return NULL;
  101. xmlDocPtr doc = xsltDocDefaultLoader((xmlChar *)filename.get(), NULL, XSLT_PARSE_OPTIONS, NULL, XSLT_LOAD_START);
  102. if (!doc)
  103. throw MakeStringException(XSLERR_InvalidSource, "Failed to parse XSLT source\n");
  104. doc->_private = static_cast<void *>(this);
  105. xsltStylesheetPtr style = xsltParseStylesheetDoc(doc);
  106. if (!style)
  107. {
  108. xmlFreeDoc(doc);
  109. throw MakeStringException(XSLERR_InvalidSource, "Failed to parse XSLT source\n");
  110. }
  111. return style;
  112. }
  113. void CLibXsltSource::compile()
  114. {
  115. if (!compiledXslt)
  116. {
  117. if ((srcType == IO_TYPE_FILE && filename.isEmpty()) || (srcType == IO_TYPE_BUFFER && text.isEmpty()))
  118. throw MakeStringException(XSLERR_MissingSource, "xslt source not set");
  119. if (compiledXslt != NULL)
  120. {
  121. xsltFreeStylesheet(compiledXslt);
  122. compiledXslt = NULL;
  123. }
  124. try
  125. {
  126. if (srcType == IO_TYPE_FILE)
  127. compiledXslt = parseXsltFile();
  128. else if (srcType == IO_TYPE_BUFFER)
  129. {
  130. xmlDocPtr xsldoc = xmlReadMemory(text.get(), text.length(), filename.get(), NULL, 0);
  131. if (!xsldoc)
  132. throw MakeStringException(XSLERR_InvalidSource, "XSLT source contains invalid XML\n");
  133. xsldoc->_private=(void*)this;
  134. compiledXslt = xsltParseStylesheetDoc(xsldoc);
  135. if (!compiledXslt)
  136. throw MakeStringException(XSLERR_InvalidSource, "Failed to parse XSLT source\n");
  137. }
  138. if (compiledXslt)
  139. compiledXslt->_private = (void*)this;
  140. }
  141. catch(...)
  142. {
  143. compiledXslt = NULL;
  144. throw;
  145. }
  146. }
  147. }
  148. class CLibXmlSource : public CInterface, implements IInterface
  149. {
  150. public:
  151. IMPLEMENT_IINTERFACE;
  152. CLibXmlSource(const char* fname)
  153. {
  154. filename.set(fname);
  155. srcType = IO_TYPE_FILE;
  156. parsedXml = NULL;
  157. }
  158. CLibXmlSource(const char* buf, int len)
  159. {
  160. text.set(buf, len);
  161. srcType = IO_TYPE_BUFFER;
  162. parsedXml = NULL;
  163. }
  164. virtual ~CLibXmlSource()
  165. {
  166. if (parsedXml)
  167. xmlFreeDoc(parsedXml);
  168. }
  169. xmlDocPtr getParsedXml();
  170. bool isCompiled() const {return parsedXml!=NULL;}
  171. public:
  172. IO_Type srcType;
  173. StringAttr filename;
  174. StringAttr text;
  175. xmlDocPtr parsedXml;
  176. };
  177. xmlDocPtr CLibXmlSource::getParsedXml()
  178. {
  179. if (!parsedXml)
  180. {
  181. if ((srcType == IO_TYPE_FILE && filename.isEmpty()) ||
  182. (srcType == IO_TYPE_BUFFER && text.isEmpty()))
  183. throw MakeStringException(XSLERR_MissingXml, "xml source not set");
  184. if (parsedXml)
  185. {
  186. xmlFreeDoc(parsedXml);
  187. parsedXml = NULL;
  188. }
  189. try
  190. {
  191. if (srcType == IO_TYPE_FILE)
  192. parsedXml = xmlParseFile(filename.get());
  193. else if (srcType == IO_TYPE_BUFFER)
  194. parsedXml = xmlReadMemory(text.get(), text.length(), "source.xml", NULL, 0);
  195. }
  196. catch(...)
  197. {
  198. parsedXml = NULL;
  199. throw;
  200. }
  201. }
  202. return parsedXml;
  203. }
  204. class CLibXsltResultTarget : public CInterface, implements IInterface
  205. {
  206. private:
  207. IO_Type destType;
  208. StringAttr filename;
  209. char* dest;
  210. int maxLen;
  211. public:
  212. IMPLEMENT_IINTERFACE;
  213. CLibXsltResultTarget(const char* _filename) : filename(_filename)
  214. {
  215. destType = IO_TYPE_FILE;
  216. }
  217. CLibXsltResultTarget(char* _buffer, int _len) : dest(_buffer), maxLen(_len)
  218. {
  219. destType = IO_TYPE_BUFFER;
  220. }
  221. void process(const char* content, int contLen)
  222. {
  223. if (destType == IO_TYPE_FILE)
  224. {
  225. Owned<IFile> f = createIFile(filename.get());
  226. Owned<IFileIO> fio = f->open(IFOwrite);
  227. fio->write(0, contLen, content);
  228. }
  229. else
  230. {
  231. if (contLen>maxLen)
  232. throw MakeStringException(XSLERR_TargetBufferToSmall, "XSLT Output greater than target buffer size");
  233. memcpy((void*)dest, content, contLen);
  234. dest[contLen] = '\0';
  235. }
  236. }
  237. };
  238. typedef void TextFunctionType(StringBuffer& out, const char* pszIn, IXslTransform* pTransform);
  239. class CLibXslFunction : public CInterface, implements IXslFunction
  240. {
  241. public:
  242. IMPLEMENT_IINTERFACE;
  243. CLibXslFunction(const char* _name, TextFunctionType* _fn, IXslTransform* trans)
  244. : name(_name), fn(_fn), parent(trans), assigned(false) {}
  245. virtual ~CLibXslFunction(){}
  246. virtual const char* getName() const
  247. {
  248. return name.get();
  249. }
  250. virtual bool isAssigned ()
  251. {
  252. return assigned;
  253. }
  254. virtual void setAssigned(bool bAssigned)
  255. {
  256. assigned = bAssigned;
  257. }
  258. virtual void setURI(const char *_uri)
  259. {
  260. if (uri.isEmpty())
  261. uri.set(_uri);
  262. else if (!streq(uri.get(), _uri))
  263. throw MakeStringException(XSLERR_ExtenrnalFunctionMultipleURIs, "The same function cannot be assigned to multiple URIs");
  264. }
  265. public:
  266. StringAttr name;
  267. StringAttr uri;
  268. TextFunctionType* fn;
  269. bool assigned;
  270. IXslTransform* parent;
  271. };
  272. class CLibXslTransform : public CInterface, implements IXslTransform
  273. {
  274. public:
  275. IMPLEMENT_IINTERFACE;
  276. CLibXslTransform();
  277. ~CLibXslTransform();
  278. virtual int transform();
  279. virtual int transform(StringBuffer &s);
  280. virtual int transform(ISocket* targetSocket);
  281. int transform(xmlChar **xmlbuff, int &len);
  282. virtual int setXmlSource(const char *pszFileName);
  283. virtual int setXmlSource(const char *pszBuffer, unsigned int nSize);
  284. virtual int setXslSource(const char *pszBuffer, unsigned int nSize, const char *cacheId, const char *rootpath);
  285. virtual int setXslNoCache(const char *pszBuffer, unsigned int nSize, const char *rootpath=NULL);
  286. virtual int loadXslFromFile(const char *pszFileName, const char *altCacheId=NULL);
  287. virtual int loadXslFromEmbedded(const char *path, const char *cacheId);
  288. virtual int setResultTarget(char *pszBuffer, unsigned int nSize);
  289. virtual int setResultTarget(const char *pszFileName);
  290. virtual int closeResultTarget();
  291. virtual int setParameter(const char *pszName, const char *pszExpression);
  292. virtual void copyParameters(IProperties *params);
  293. virtual int setStringParameter(const char *pszName, const char* pszString);
  294. bool checkSanity();
  295. virtual int setIncludeHandler(IIncludeHandler* handler)
  296. {
  297. includeHandler.set(handler);
  298. return 0;
  299. }
  300. virtual IXslFunction* createExternalFunction( const char* name, TextFunctionType *fn)
  301. {
  302. return new CLibXslFunction(name, fn, this);
  303. }
  304. virtual int setExternalFunction(const char* ns, IXslFunction* xfn, bool set);
  305. IXslFunction* queryExternalFunction(const char *ns, const char* name)
  306. {
  307. StringBuffer s(ns);
  308. return functions.getValue(s.append(':').append(name).str());
  309. }
  310. virtual const char* getLastError() const
  311. {
  312. return ""; //was xalan specific pass through
  313. }
  314. virtual const char* getMessages() const
  315. {
  316. return messages.str();
  317. }
  318. virtual void setUserData(void* _userData)
  319. {
  320. userData = _userData;
  321. }
  322. virtual void* getUserData() const
  323. {
  324. return userData;
  325. }
  326. IProperties *ensureParameters()
  327. {
  328. if (!xslParameters)
  329. xslParameters.setown(createProperties());
  330. return xslParameters.get();
  331. }
  332. IMultiException *ensureExceptions()
  333. {
  334. if (!exceptions)
  335. exceptions.setown(MakeMultiException());
  336. return exceptions.get();
  337. }
  338. void clearExceptions(){exceptions.clear();}
  339. void clearMessages(){messages.clear();}
  340. public:
  341. Owned<IProperties> xslParameters;
  342. Owned<CLibXsltSource> xslSrc;
  343. Owned<CLibXmlSource> xmlSrc;
  344. Owned<CLibXsltResultTarget> target;
  345. Owned<IIncludeHandler> includeHandler;
  346. Owned<IXslFunction> msgfn;
  347. MapStringToMyClass<IXslFunction> functions;
  348. Owned<IMultiException> exceptions;
  349. StringBuffer messages;
  350. void *userData;
  351. };
  352. CLibXslTransform::CLibXslTransform()
  353. {
  354. userData = NULL;
  355. msgfn.setown(createExternalFunction("message", libxsltCustomMessageHandler));
  356. setExternalFunction(SEISINT_XSLTEXT_NAMESPACE, msgfn, true);
  357. }
  358. CLibXslTransform::~CLibXslTransform()
  359. {
  360. }
  361. void CLibXslTransform::copyParameters(IProperties *params)
  362. {
  363. if (params)
  364. {
  365. Owned<IPropertyIterator> it = params->getIterator();
  366. ForEach(*it.get())
  367. {
  368. const char *name = it->getPropKey();
  369. const char *value = params->queryProp(name);
  370. setParameter(name, value);
  371. }
  372. }
  373. }
  374. int CLibXslTransform::setExternalFunction(const char* ns, IXslFunction* xfn, bool set)
  375. {
  376. if (!xfn)
  377. return 0;
  378. CLibXslFunction *cfn = dynamic_cast<CLibXslFunction*>(xfn);
  379. if (!cfn)
  380. throw MakeStringException(XSLERR_ExternalFunctionIncompatible, "External Funciton not created for LIBXSLT");
  381. cfn->setURI(ns);
  382. if (set)
  383. {
  384. StringBuffer s(ns);
  385. s.append(':').append(xfn->getName());
  386. if (!functions.getValue(s.str()))
  387. functions.setValue(s.str(), xfn);
  388. }
  389. return 0;
  390. }
  391. bool CLibXslTransform::checkSanity()
  392. {
  393. return (xslSrc.get() != NULL && xmlSrc.get() != NULL);
  394. }
  395. CLibXslTransform *getXsltTransformObject(xsltTransformContextPtr x)
  396. {
  397. if (!x)
  398. return NULL;
  399. if (!x->_private)
  400. return NULL;
  401. return static_cast<CLibXslTransform *>(x->_private);
  402. }
  403. void globalLibXsltExtensionHandler(xmlXPathParserContextPtr ctxt, int nargs);
  404. static void libxsltErrorMsgHandler(void *ctx, const char *format, ...)
  405. {
  406. if (!ctx)
  407. return;
  408. if (format && *format == '\n')
  409. return;
  410. CLibXslTransform *ctrans = (CLibXslTransform*)ctx;//getXsltTransformObject((xsltTransformContextPtr)ctx);
  411. if (!ctrans)
  412. return;
  413. va_list args;
  414. va_start(args, format);
  415. ctrans->ensureExceptions()->append(*MakeStringExceptionVA(XSLERR_TransformError, format, args));
  416. va_end(args);
  417. }
  418. int CLibXslTransform::transform(xmlChar **xmlbuff, int &len)
  419. {
  420. clearExceptions();
  421. clearMessages();
  422. xsltSetGenericErrorFunc(this, libxsltErrorMsgHandler);
  423. if (!xmlSrc)
  424. throw MakeStringException(XSLERR_MissingXml, "XSLT Transform missing XML");
  425. else if (!xslSrc)
  426. throw MakeStringException(XSLERR_MissingSource, "XSL source not set");
  427. StringArray params;
  428. if (xslParameters)
  429. {
  430. Owned<IPropertyIterator> it = xslParameters->getIterator();
  431. ForEach(*it)
  432. {
  433. const char *name = it->getPropKey();
  434. if (!name || !*name)
  435. continue;
  436. const char *val = xslParameters->queryProp(name);
  437. if (!val || !*val)
  438. continue;
  439. params.append(name);
  440. params.append(val);
  441. }
  442. }
  443. xmlDocPtr xmldoc = xmlSrc->getParsedXml();
  444. xslSrc->setIncludeHandler(includeHandler.get());
  445. xsltStylesheetPtr xsldoc = xslSrc->getCompiledXslt();
  446. xsltTransformContextPtr ctxt = xsltNewTransformContext(xsldoc, xmldoc);
  447. if (!ctxt)
  448. throw MakeStringException(XSLERR_CouldNotCreateTransform, "Failed creating libxslt Transform Context");
  449. ctxt->_private = this;
  450. HashIterator h(functions);
  451. ForEach (h)
  452. {
  453. IXslFunction *fn = functions.mapToValue(&h.query());
  454. CLibXslFunction *cfn = dynamic_cast<CLibXslFunction*>(fn);
  455. if (cfn && cfn->name.length())
  456. xsltRegisterExtFunction(ctxt, (const xmlChar *) cfn->name.get(), (const xmlChar *) cfn->uri.str(), globalLibXsltExtensionHandler);
  457. }
  458. xsltSetCtxtParseOptions(ctxt, XSLT_PARSE_OPTIONS);
  459. MemoryBuffer mp;
  460. if (params.length())
  461. mp.append(sizeof(const char *) * params.length(), params.getArray()).append((unsigned __int64)0);
  462. xmlDocPtr res = xsltApplyStylesheetUser(xsldoc, xmldoc, (mp.length()) ? (const char**)mp.toByteArray() : NULL, NULL, NULL, ctxt);
  463. if (!res)
  464. {
  465. if (exceptions && exceptions->ordinality())
  466. throw exceptions.getClear();
  467. throw MakeStringException(XSLERR_TransformFailed, "Failed running xlst using libxslt.");
  468. }
  469. xsltTransformState stateAfterTransform = ctxt->state;
  470. try
  471. {
  472. xsltFreeTransformContext(ctxt);
  473. xsltSaveResultToString(xmlbuff, &len, res, xsldoc);
  474. }
  475. catch(...)
  476. {
  477. xmlFreeDoc(res);
  478. xmlFree(xmlbuff);
  479. throw MakeStringException(XSLERR_TransformFailed, "Failed processing libxslt transform output");
  480. }
  481. xmlFreeDoc(res);
  482. if (exceptions && exceptions->ordinality())
  483. {
  484. if (stateAfterTransform != XSLT_STATE_OK)
  485. {
  486. throw exceptions.getClear();
  487. }
  488. else
  489. {
  490. StringBuffer strErrMsg;
  491. exceptions.get()->errorMessage(strErrMsg);
  492. messages.set(strErrMsg.str());
  493. }
  494. }
  495. return 0;
  496. }
  497. int CLibXslTransform::transform(StringBuffer &s)
  498. {
  499. int len = 0;
  500. xmlChar *xmlbuff = NULL;
  501. transform(&xmlbuff, len);
  502. if (len && xmlbuff)
  503. {
  504. s.append(len, (char *) xmlbuff);
  505. xmlFree(xmlbuff);
  506. }
  507. return 0;
  508. }
  509. int CLibXslTransform::transform()
  510. {
  511. int len = 0;
  512. xmlChar *xmlbuff = NULL;
  513. transform(&xmlbuff, len);
  514. if (len && xmlbuff)
  515. {
  516. target->process((const char *) xmlbuff, len);
  517. xmlFree(xmlbuff);
  518. }
  519. return 0;
  520. }
  521. int CLibXslTransform::transform(ISocket* targetSocket)
  522. {
  523. int len = 0;
  524. xmlChar *xmlbuff = NULL;
  525. transform(&xmlbuff, len);
  526. if (len && xmlbuff)
  527. {
  528. targetSocket->write((const void *) xmlbuff, (size32_t) len);
  529. xmlFree(xmlbuff);
  530. }
  531. return 0;
  532. }
  533. int CLibXslTransform::setXmlSource(const char *pszFileName)
  534. {
  535. xmlSrc.setown(new CLibXmlSource(pszFileName));
  536. return 0;
  537. }
  538. int CLibXslTransform::setXmlSource(const char *pszBuffer, unsigned int nSize)
  539. {
  540. xmlSrc.setown(new CLibXmlSource(pszBuffer, nSize));
  541. return 0;
  542. }
  543. int CLibXslTransform::setXslSource(const char *pszBuffer, unsigned int nSize, const char *cacheId, const char *rootpath)
  544. {
  545. xslSrc.setown(new CLibXsltSource(pszBuffer, nSize, cacheId));
  546. return 0;
  547. }
  548. int CLibXslTransform::loadXslFromEmbedded(const char *path, const char *cacheId)
  549. {
  550. xslSrc.setown(new CLibXsltSource(includeHandler.get(), path, cacheId));
  551. return 0;
  552. }
  553. int CLibXslTransform::setXslNoCache(const char *pszBuffer, unsigned int nSize, const char *rootpath)
  554. {
  555. xslSrc.setown(new CLibXsltSource(pszBuffer, nSize, NULL));
  556. return 0;
  557. }
  558. int CLibXslTransform::loadXslFromFile(const char *pszFileName, const char *altCacheId)
  559. {
  560. xslSrc.setown(new CLibXsltSource(pszFileName));
  561. return 0;
  562. }
  563. int CLibXslTransform::setResultTarget(const char *pszFileName)
  564. {
  565. target.setown(new CLibXsltResultTarget(pszFileName));
  566. return 0;
  567. }
  568. int CLibXslTransform::setResultTarget(char *pszBuffer, unsigned int nSize)
  569. {
  570. target.setown(new CLibXsltResultTarget(pszBuffer, nSize));
  571. return 0;
  572. }
  573. int CLibXslTransform::closeResultTarget()
  574. {
  575. return 0;
  576. }
  577. int CLibXslTransform::setParameter(const char *pszName, const char *pszExpression)
  578. {
  579. if (pszName && *pszName)
  580. ensureParameters()->setProp(pszName, pszExpression);
  581. return 0;
  582. }
  583. int CLibXslTransform::setStringParameter(const char *pszName, const char* pszString)
  584. {
  585. if (pszName && *pszName)
  586. ensureParameters()->setProp(pszName, StringBuffer("'").append(pszString).append("'").str());
  587. return 0;
  588. }
  589. class CLibXslProcessor : public CInterface, implements IXslProcessor
  590. {
  591. public:
  592. IMPLEMENT_IINTERFACE;
  593. CLibXslProcessor();
  594. ~CLibXslProcessor();
  595. virtual IXslTransform *createXslTransform();
  596. virtual int execute(IXslTransform *pITransform);
  597. virtual int setDefIncludeHandler(IIncludeHandler* handler){includeHandler.set(handler); return 0;}
  598. IIncludeHandler* queryDefIncludeHandler(){return includeHandler.get();}
  599. virtual void setCacheTimeout(int timeout);
  600. virtual int getCacheTimeout();
  601. public:
  602. Owned<IIncludeHandler> includeHandler;
  603. int m_cachetimeout;
  604. };
  605. CLibXslProcessor::CLibXslProcessor()
  606. {
  607. m_cachetimeout = XSLT_DEFAULT_CACHETIMEOUT;
  608. xmlInitMemory();
  609. xmlInitParser();
  610. xmlSubstituteEntitiesDefault(1);
  611. xmlThrDefSaveNoEmptyTags(1);
  612. xmlLoadExtDtdDefaultValue = 1;
  613. xsltMaxDepth = 20000;
  614. xsltSetLoaderFunc(NULL);
  615. originalLibXsltIncludeHandler = xsltDocDefaultLoader;
  616. xsltSetLoaderFunc(globalLibXsltIncludeHandler);
  617. exsltRegisterAll();
  618. xsltSetGenericErrorFunc(NULL, libxsltErrorMsgHandler);
  619. }
  620. CLibXslProcessor::~CLibXslProcessor()
  621. {
  622. xsltCleanupGlobals();
  623. xmlCleanupParser();
  624. xmlCleanupMemory();
  625. }
  626. static CLibXslProcessor xslProcessor;
  627. extern IXslProcessor* getXslProcessor()
  628. {
  629. return LINK(&xslProcessor);
  630. }
  631. IXslTransform *CLibXslProcessor::createXslTransform()
  632. {
  633. return new CLibXslTransform();
  634. }
  635. int CLibXslProcessor::execute(IXslTransform *pITransform)
  636. {
  637. return ((CLibXslTransform*)pITransform)->transform();
  638. }
  639. void CLibXslProcessor::setCacheTimeout(int timeout)
  640. {
  641. m_cachetimeout = timeout;
  642. IXslCache* xslcache = getXslCache2();
  643. if (xslcache)
  644. xslcache->setCacheTimeout(timeout);
  645. }
  646. int CLibXslProcessor::getCacheTimeout()
  647. {
  648. return m_cachetimeout;
  649. }
  650. CLibXsltSource *getXsltStylesheetSourceObject(xsltStylesheetPtr x)
  651. {
  652. if (!x)
  653. return NULL;
  654. if (x->_private)
  655. return static_cast<CLibXsltSource *>(x->_private);
  656. if (!x->doc || !x->doc->_private)
  657. return NULL;
  658. x->_private = x->doc->_private; //initialy stored in root xstl xml document
  659. return static_cast<CLibXsltSource *>(x->_private);
  660. }
  661. xmlDocPtr libXsltIncludeHandler(const xmlChar * URI, xmlDictPtr dict, int options, IIncludeHandler* handler, xsltLoadType type)
  662. {
  663. bool mbContainsPath=false;
  664. MemoryBuffer mb;
  665. StringBuffer decodedURI;
  666. appendDecodedURL(decodedURI, (const char *)URI);
  667. if (strchr(decodedURI.str(), '%')) //libxstl seems to double encode
  668. {
  669. StringBuffer s;
  670. appendDecodedURL(s, decodedURI.str());
  671. decodedURI.swapWith(s);
  672. }
  673. if (!handler->getInclude(decodedURI, mb, mbContainsPath))
  674. return originalLibXsltIncludeHandler(URI, dict, options, NULL, type);
  675. if (mbContainsPath)
  676. return originalLibXsltIncludeHandler((const xmlChar *)mb.append((char)0).toByteArray(), dict, options, NULL, type);
  677. if (mb.length())
  678. return xmlReadMemory(mb.toByteArray(), mb.length(), (const char *)URI, NULL, 0);
  679. return NULL;
  680. }
  681. IIncludeHandler* getXsltStylesheetIncludeHandler(xsltStylesheetPtr x, IIncludeHandler *def)
  682. {
  683. CLibXsltSource *src = getXsltStylesheetSourceObject(x);
  684. return (src && src->includeHandler) ? src->includeHandler.get() : def;
  685. }
  686. xmlDocPtr globalLibXsltIncludeHandler(const xmlChar * URI, xmlDictPtr dict, int options, void *ctx, xsltLoadType type)
  687. {
  688. xsltStylesheetPtr x = (xsltStylesheetPtr)ctx;
  689. if (type == XSLT_LOAD_DOCUMENT)
  690. x = ((xsltTransformContextPtr)ctx)->style;
  691. IIncludeHandler* handler = getXsltStylesheetIncludeHandler(x, xslProcessor.queryDefIncludeHandler());
  692. if (handler)
  693. return libXsltIncludeHandler(URI, dict, options, handler, type);
  694. return originalLibXsltIncludeHandler(URI, dict, options, ctx, type);
  695. }
  696. void libxsltCustomMessageHandler(StringBuffer& out, const char* in, IXslTransform* trans)
  697. {
  698. CLibXslTransform *ctrans = dynamic_cast<CLibXslTransform *>(trans);
  699. if (!ctrans)
  700. return;
  701. ctrans->messages.append(in).append(';');
  702. out.append(in);
  703. }
  704. void globalLibXsltExtensionHandler(xmlXPathParserContextPtr ctxt, int nargs)
  705. {
  706. const xmlChar *uri = ctxt->context->functionURI;
  707. const xmlChar *name = ctxt->context->function;
  708. xsltTransformContextPtr tctxt = xsltXPathGetTransformContext(ctxt);
  709. if (!tctxt)
  710. {
  711. xsltGenericError(xsltGenericErrorContext, "failed to get the transformation context\n");
  712. return;
  713. }
  714. if (nargs!=1)
  715. {
  716. VStringBuffer msg("Extension %s:%s - called", uri, name);
  717. if (!nargs)
  718. msg.append(" without any arguments\n");
  719. else
  720. msg.append(" with too many arguments\n");
  721. xsltGenericError(xsltGenericErrorContext, "%s", msg.str());
  722. ctxt->error = XPATH_INVALID_ARITY;
  723. return;
  724. }
  725. xmlChar *text =xmlXPathPopString(ctxt);
  726. CLibXslTransform *trns = getXsltTransformObject(tctxt);
  727. if (!trns)
  728. {
  729. xsltGenericError(xsltGenericErrorContext, "{%s}%s: IXslTransform not found\n", uri, name);
  730. return;
  731. }
  732. StringBuffer out;
  733. IXslFunction *xslfn = trns->queryExternalFunction((const char *)uri, (const char *)name);
  734. if (!xslfn)
  735. {
  736. xsltGenericError(xsltGenericErrorContext, "{%s}%s: IXslFuntionTransform not found\n", uri, name);
  737. return;
  738. }
  739. CLibXslFunction *cfn = dynamic_cast<CLibXslFunction *>(xslfn);
  740. cfn->fn(out, (const char *)text, trns);
  741. valuePush(ctxt, xmlXPathNewCString(out.str()));
  742. }