From c5a11763985172f54d0da8a2a2778f882f3656e5 Mon Sep 17 00:00:00 2001 From: Adrian Kummerländer Date: Sun, 25 May 2014 21:49:59 +0200 Subject: Implemented basic external "execute" function * enables execution of external programs ** second parameter is passed to stdin ** stdout is captured and returned ** based on booost::process * this was implemented to enable access to external content preprocessors such as markdown --- CMakeLists.txt | 1 + README.md | 2 ++ src/function/execute.cc | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ src/function/execute.h | 28 ++++++++++++++++++ src/plattform_guard.cc | 7 +++++ 5 files changed, 115 insertions(+) create mode 100644 src/function/execute.cc create mode 100644 src/function/execute.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e09c096..442c215 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ set( src/function/read_xml_file.cc src/function/read_directory.cc src/function/transform.cc + src/function/execute.cc src/support/filesystem_context.cc src/support/stylesheet_parameter_guard.cc src/support/xalan_string.cc diff --git a/README.md b/README.md index 867de8f..e051979 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Contrary to popular opinion I actually like XSLT as a content transformation lan - external `read-xml-file` function for read-only access to XML files - external `read-directory` function for read-only directory traversal - external `transform` function for executing transformations inside transformations +- external `execute` function for executing external applications and capturing their output ## Requirements: @@ -21,3 +22,4 @@ Contrary to popular opinion I actually like XSLT as a content transformation lan - Apache [Xerces](https://xerces.apache.org/) XML Library - Boost [Filesystem](http://www.boost.org/doc/libs/1_55_0/libs/filesystem/doc/index.htm) - Boost [Program Options](http://www.boost.org/doc/libs/1_55_0/doc/html/program_options.html) +- Boost [Process](http://www.highscore.de/boost/process/index.html) diff --git a/src/function/execute.cc b/src/function/execute.cc new file mode 100644 index 0000000..f19ba75 --- /dev/null +++ b/src/function/execute.cc @@ -0,0 +1,77 @@ +#include "execute.h" + +#include +#include +#include + +#include + +#include "support/xerces_string_guard.h" +#include "support/dom/result_node_facade.h" + +namespace InputXSLT { + +xercesc::DOMDocument* FunctionExecute::constructDocument( + const InputXSLT::FilesystemContext&, + const FunctionBase::parameter_tuple& parameters +) { + const std::string& executablePath( + std::get<0>(parameters) + ); + + const std::string& stdinText( + std::get<1>(parameters) + ); + + xercesc::DOMDocument* const domDocument( + xercesc::DOMImplementation::getImplementation()->createDocument( + nullptr, + *XercesStringGuard("content"), + nullptr + ) + ); + + xercesc::DOMNode* const rootNode( + domDocument->getDocumentElement() + ); + + boost::process::context context; + context.stdout_behavior = boost::process::capture_stream(); + context.stdin_behavior = boost::process::capture_stream(); + + boost::process::child process( + boost::process::launch( + executablePath, + std::vector{""}, + context + ) + ); + + boost::process::postream& inputStream = process.get_stdin(); + boost::process::pistream& outputStream = process.get_stdout(); + + inputStream << stdinText; + inputStream.close(); + + const std::string resultText( + (std::istreambuf_iterator(outputStream)), + (std::istreambuf_iterator()) + ); + + boost::process::status status = process.wait(); + + if ( status.exited() ) { + ResultNodeFacade result(domDocument, rootNode, "result"); + + result.setValueNode("code", std::to_string(status.exit_status())); + result.setValueNode("output", resultText); + } else { + ResultNodeFacade result(domDocument, rootNode, "error"); + + result.setValueNode("code", std::to_string(status.exit_status())); + } + + return domDocument; +} + +} diff --git a/src/function/execute.h b/src/function/execute.h new file mode 100644 index 0000000..12167da --- /dev/null +++ b/src/function/execute.h @@ -0,0 +1,28 @@ +#ifndef INPUTXSLT_SRC_FUNCTION_EXECUTE_H_ +#define INPUTXSLT_SRC_FUNCTION_EXECUTE_H_ + +#include "base.h" + +namespace InputXSLT { + +class FunctionExecute : public FunctionBase< + FunctionExecute, + std::string, + std::string +> { + public: + using FunctionBase::FunctionBase; + + protected: + friend FunctionBase; + + xercesc::DOMDocument* constructDocument( + const FilesystemContext&, + const FunctionBase::parameter_tuple& + ); + +}; + +} + +#endif // INPUTXSLT_SRC_FUNCTION_EXECUTE_H_ diff --git a/src/plattform_guard.cc b/src/plattform_guard.cc index d66c8b5..ff4de08 100644 --- a/src/plattform_guard.cc +++ b/src/plattform_guard.cc @@ -10,6 +10,7 @@ #include "function/read_xml_file.h" #include "function/read_directory.h" #include "function/transform.h" +#include "function/execute.h" namespace InputXSLT { @@ -45,6 +46,12 @@ PlattformGuard::PlattformGuard(const std::vector& path): xalan::XalanDOMString("transform"), InputXSLT::FunctionTransform(&this->include_resolver_) ); + + xalan::XalanTransformer::installExternalFunctionGlobal( + customNamespace, + xalan::XalanDOMString("execute"), + InputXSLT::FunctionExecute(&this->include_resolver_) + ); } PlattformGuard::~PlattformGuard() { -- cgit v1.2.3