diff options
author | Adrian Kummerlaender | 2014-08-16 23:30:36 +0200 |
---|---|---|
committer | Adrian Kummerlaender | 2014-08-16 23:30:36 +0200 |
commit | f6ff54c492df81018cf48da039ee681508f88e46 (patch) | |
tree | 0659e0f5bf4529b8c83bebc87119607638f98b7f | |
parent | 7f6611cded8c1591f1aa1a4c7d70505cb21e7967 (diff) | |
download | InputXSLT-f6ff54c492df81018cf48da039ee681508f88e46.tar InputXSLT-f6ff54c492df81018cf48da039ee681508f88e46.tar.gz InputXSLT-f6ff54c492df81018cf48da039ee681508f88e46.tar.bz2 InputXSLT-f6ff54c492df81018cf48da039ee681508f88e46.tar.lz InputXSLT-f6ff54c492df81018cf48da039ee681508f88e46.tar.xz InputXSLT-f6ff54c492df81018cf48da039ee681508f88e46.tar.zst InputXSLT-f6ff54c492df81018cf48da039ee681508f88e46.zip |
Implemented primitive optional parameter support for external functions
* renamed FunctionExternalTextFormatter into FunctionExternalCommand
** the goal is to provide a general interface to a variety of external commands
*** e.g. not just text formatters but system utilities for file management and so on
** this requires the stdin parameter to be optional as not all external commands require stdin input
* implemented "filter_derived" helper template to determine amount of optional parameters
** optional parameters are defined as "boost::optional" specializations
*** they in turn can be detected by checking if "boost::optional_detail::optional_tag" is a base class
* "callConstructDocument" member method of "FunctionBase" performs additional bounds checking of parameter vector
* "boost::optional<std::string>" specific member overload was added to "XObjectValue" helper class
** we will have to provide full specializations for all optional types as C++ prohibits partial member function template specialization
* renamed the external function in "PlattformGuard"
* changed README.md and test cases accordingly
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | ixslt.cc | 4 | ||||
-rw-r--r-- | src/function/base.h | 27 | ||||
-rw-r--r-- | src/function/external_command.cc (renamed from src/function/external_text_formatter.cc) | 30 | ||||
-rw-r--r-- | src/function/external_command.h | 31 | ||||
-rw-r--r-- | src/function/external_text_formatter.h | 30 | ||||
-rw-r--r-- | src/platform_guard.cc | 6 | ||||
-rw-r--r-- | src/support/filesystem_context.h | 2 | ||||
-rw-r--r-- | src/support/include_entity_resolver.cc | 2 | ||||
-rw-r--r-- | src/support/include_entity_resolver.h | 2 | ||||
-rw-r--r-- | src/support/type/filter.h | 24 | ||||
-rw-r--r-- | src/support/type/xobject_value.cc | 13 | ||||
-rw-r--r-- | test/external_text_formatter/reference.xml | 2 | ||||
-rw-r--r-- | test/external_text_formatter/transformation.xsl | 2 |
15 files changed, 115 insertions, 66 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f19bb1..32d8db2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,7 @@ set( src/function/read_directory.cc src/function/transform.cc src/function/generate.cc - src/function/external_text_formatter.cc + src/function/external_command.cc src/support/filesystem_context.cc src/support/xalan_string.cc src/support/include_entity_resolver.cc @@ -12,7 +12,7 @@ Contrary to popular opinion I actually like XSLT as a content transformation lan - external `read-directory` function for read-only directory traversal - external `transform` function for executing transformations inside transformations - external `generate` function for executing transformations and committing the result directly to the filesystem -- external `external-text-formatter` function for executing text formatters and capturing their XML output +- external `external-command` function for executing external commands such as text formatters and capturing their output - external `write-file` function for writing files ## Examples: @@ -24,7 +24,7 @@ The `test` directory contains black-box test cases for every external function p - [`InputXSLT:read-directory`](test/read_directory/transformation.xsl) - [`InputXSLT:transform`](test/transform/transformation.xsl) - [`InputXSLT:generate`](test/generate/transformation.xsl) -- [`InputXSLT:external-text-formatter`](test/external_text_formatter/transformation.xsl) (requires [markdown.pl](http://daringfireball.net/projects/markdown/)) +- [`InputXSLT:external-command` (text formatting)](test/external_text_formatter/transformation.xsl) (requires [markdown.pl](http://daringfireball.net/projects/markdown/)) - [`InputXSLT:write-file`](test/write_file/transformation.xsl) Concepts of how static sites may be generated using InputXSLT are being evaluated in [TestXSLT](https://github.com/KnairdA/TestXSLT). @@ -2,8 +2,8 @@ #include <xalanc/PlatformSupport/XalanStdOutputStream.hpp> #include <xalanc/XMLSupport/FormatterToXML.hpp> -#include "boost/optional.hpp" -#include "boost/program_options.hpp" +#include <boost/optional.hpp> +#include <boost/program_options.hpp> #include <boost/filesystem/fstream.hpp> #include <string> diff --git a/src/function/base.h b/src/function/base.h index 2d1e4c4..a8f93b9 100644 --- a/src/function/base.h +++ b/src/function/base.h @@ -5,6 +5,8 @@ #include <xalanc/XPath/Function.hpp> #include <xalanc/XPath/XObject.hpp> +#include <boost/optional.hpp> + #include <memory> #include <tuple> @@ -14,6 +16,7 @@ #include "support/include_entity_resolver.h" #include "support/dom/document_cache.h" #include "support/type/sequence.h" +#include "support/type/filter.h" #include "support/type/xobject_value.h" namespace InputXSLT { @@ -23,7 +26,13 @@ template < typename... Types > class FunctionBase : public xalan::Function { - static const std::size_t parameter_count = sizeof...(Types); + static const std::size_t parameter_count = sizeof...(Types); + static const std::size_t optional_parameter_count = std::tuple_size< + typename filter_derived< + boost::optional_detail::optional_tag, + Types... + >::type + >::value; public: FunctionBase(IncludeEntityResolver* resolver): @@ -108,16 +117,20 @@ class FunctionBase : public xalan::Function { valueGetter.get<typename std::tuple_element< Index, std::tuple<Types...> - >::type>(parameters[Index])... + >::type>( + Index < parameters.size() + ? parameters[Index] + : xalan::XObjectPtr() + )... ) ); } inline void validateParameters( - const XObjectArgVectorType& parameters, + const XObjectArgVectorType& parameters, xalan::XPathExecutionContext& executionContext, - xalan::XalanNode* context, - const xalan::Locator* locator + xalan::XalanNode* context, + const xalan::Locator* locator ) const { const bool anyNull = std::any_of( parameters.begin(), @@ -127,7 +140,9 @@ class FunctionBase : public xalan::Function { } ); - if ( parameters.size() != parameter_count || anyNull ) { + if ( parameters.size() > parameter_count || + parameters.size() < optional_parameter_count || + anyNull ) { xalan::XPathExecutionContext::GetAndReleaseCachedString guard( executionContext ); diff --git a/src/function/external_text_formatter.cc b/src/function/external_command.cc index 03902e9..bd2bf84 100644 --- a/src/function/external_text_formatter.cc +++ b/src/function/external_command.cc @@ -1,4 +1,4 @@ -#include "external_text_formatter.h" +#include "external_command.h" #include <xalanc/XSLT/XSLTInputSource.hpp> @@ -39,9 +39,9 @@ inline xercesc::DOMNode* importDocumentElement( namespace InputXSLT { -DomDocumentCache::document_ptr FunctionExternalTextFormatter::constructDocument( - std::string formatterCommand, - std::string stdinText +DomDocumentCache::document_ptr FunctionExternalCommand::constructDocument( + std::string command, + boost::optional<std::string> stdinText ) const { DomDocumentCache::document_ptr domDocument( DomDocumentCache::createDocument("content") @@ -52,23 +52,21 @@ DomDocumentCache::document_ptr FunctionExternalTextFormatter::constructDocument( context.stdout_behavior = boost::process::capture_stream(); context.stdin_behavior = boost::process::capture_stream(); - boost::process::child formatterProcess( - boost::process::launch_shell( - formatterCommand, - context - ) + boost::process::child commandProcess( + boost::process::launch_shell(command, context) ); - boost::process::postream& inputStream = formatterProcess.get_stdin(); - boost::process::pistream& outputStream = formatterProcess.get_stdout(); - - inputStream << stdinText; - inputStream.close(); + if ( stdinText ) { + boost::process::postream& inputStream = commandProcess.get_stdin(); + inputStream << *stdinText; + inputStream.close(); + } - boost::process::status status = formatterProcess.wait(); + boost::process::pistream& outputStream = commandProcess.get_stdout(); + boost::process::status status = commandProcess.wait(); ResultNodeFacade result(domDocument.get(), "output"); - result.setAttribute("formatter", formatterCommand); + result.setAttribute("command", command); result.setAttribute("code", std::to_string(status.exit_status())); if ( status.exited() ) { diff --git a/src/function/external_command.h b/src/function/external_command.h new file mode 100644 index 0000000..8af5079 --- /dev/null +++ b/src/function/external_command.h @@ -0,0 +1,31 @@ +#ifndef INPUTXSLT_SRC_FUNCTION_EXTERNAL_COMMAND_H_ +#define INPUTXSLT_SRC_FUNCTION_EXTERNAL_COMMAND_H_ + +#include <boost/filesystem.hpp> +#include <boost/optional.hpp> + +#include "base.h" + +namespace InputXSLT { + +class FunctionExternalCommand : public FunctionBase< + FunctionExternalCommand, + std::string, + boost::optional<std::string> +> { + public: + using FunctionBase::FunctionBase; + + protected: + friend FunctionBase; + + DomDocumentCache::document_ptr constructDocument( + std::string, + boost::optional<std::string> + ) const; + +}; + +} + +#endif // INPUTXSLT_SRC_FUNCTION_EXTERNAL_COMMAND_H_ diff --git a/src/function/external_text_formatter.h b/src/function/external_text_formatter.h deleted file mode 100644 index 4788784..0000000 --- a/src/function/external_text_formatter.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef INPUTXSLT_SRC_FUNCTION_EXTERNAL_TEXT_FORMATTER_H_ -#define INPUTXSLT_SRC_FUNCTION_EXTERNAL_TEXT_FORMATTER_H_ - -#include <boost/filesystem.hpp> - -#include "base.h" - -namespace InputXSLT { - -class FunctionExternalTextFormatter : public FunctionBase< - FunctionExternalTextFormatter, - std::string, - std::string -> { - public: - using FunctionBase::FunctionBase; - - protected: - friend FunctionBase; - - DomDocumentCache::document_ptr constructDocument( - std::string, - std::string - ) const; - -}; - -} - -#endif // INPUTXSLT_SRC_FUNCTION_EXTERNAL_TEXT_FORMATTER_H_ diff --git a/src/platform_guard.cc b/src/platform_guard.cc index 6be5b4a..f50d976 100644 --- a/src/platform_guard.cc +++ b/src/platform_guard.cc @@ -11,7 +11,7 @@ #include "function/read_directory.h" #include "function/transform.h" #include "function/generate.h" -#include "function/external_text_formatter.h" +#include "function/external_command.h" namespace InputXSLT { @@ -56,8 +56,8 @@ PlatformGuard::PlatformGuard(const std::vector<std::string>& path): xalan::XalanTransformer::installExternalFunctionGlobal( customNamespace, - xalan::XalanDOMString("external-text-formatter"), - InputXSLT::FunctionExternalTextFormatter(&this->include_resolver_) + xalan::XalanDOMString("external-command"), + InputXSLT::FunctionExternalCommand(&this->include_resolver_) ); } diff --git a/src/support/filesystem_context.h b/src/support/filesystem_context.h index f3875a3..c00fe29 100644 --- a/src/support/filesystem_context.h +++ b/src/support/filesystem_context.h @@ -4,7 +4,7 @@ #include <xalanc/XalanDOM/XalanDOMString.hpp> #include <xalanc/XPath/Function.hpp> -#include "boost/filesystem.hpp" +#include <boost/filesystem.hpp> #include <string> #include <functional> diff --git a/src/support/include_entity_resolver.cc b/src/support/include_entity_resolver.cc index deac1d5..197b217 100644 --- a/src/support/include_entity_resolver.cc +++ b/src/support/include_entity_resolver.cc @@ -2,7 +2,7 @@ #include <xercesc/framework/LocalFileInputSource.hpp> -#include "boost/filesystem.hpp" +#include <boost/filesystem.hpp> #include "support/xalan_string.h" #include "support/xerces_string_guard.h" diff --git a/src/support/include_entity_resolver.h b/src/support/include_entity_resolver.h index ea5fb7a..e7c5542 100644 --- a/src/support/include_entity_resolver.h +++ b/src/support/include_entity_resolver.h @@ -4,7 +4,7 @@ #include <xercesc/sax/EntityResolver.hpp> #include <xercesc/sax/InputSource.hpp> -#include "boost/optional.hpp" +#include <boost/optional.hpp> #include <string> #include <vector> diff --git a/src/support/type/filter.h b/src/support/type/filter.h new file mode 100644 index 0000000..4a0e19f --- /dev/null +++ b/src/support/type/filter.h @@ -0,0 +1,24 @@ +#ifndef INPUTXSLT_SRC_SUPPORT_TYPE_FILTER_H_ +#define INPUTXSLT_SRC_SUPPORT_TYPE_FILTER_H_ + +#include <tuple> +#include <type_traits> + +namespace InputXSLT { + +template < + typename BaseReference, + typename Head, + typename... Tail +> +struct filter_derived { + typedef typename std::conditional< + std::is_base_of<BaseReference, Head>::value, + std::tuple<Head, Tail...>, + std::tuple<Tail...> + >::type type; +}; + +} + +#endif // INPUTXSLT_SRC_SUPPORT_TYPE_FILTER_H_ diff --git a/src/support/type/xobject_value.cc b/src/support/type/xobject_value.cc index 9bb6648..e457a69 100644 --- a/src/support/type/xobject_value.cc +++ b/src/support/type/xobject_value.cc @@ -4,7 +4,8 @@ #include <xalanc/XalanDOM/XalanDocumentFragment.hpp> #include <boost/algorithm/string.hpp> -#include "boost/filesystem.hpp" +#include <boost/filesystem.hpp> +#include <boost/optional.hpp> #include <string> @@ -27,6 +28,16 @@ std::string XObjectValue::get<std::string>( } template <> +boost::optional<std::string> XObjectValue::get<boost::optional<std::string>>( + const xalan::XObjectPtr& ptr) const { + if ( ptr.null() ) { + return boost::optional<std::string>(); + } else { + return this->get<std::string>(ptr); + } +} + +template <> boost::filesystem::path XObjectValue::get<boost::filesystem::path>( const xalan::XObjectPtr& ptr) const { const std::string rawPath( diff --git a/test/external_text_formatter/reference.xml b/test/external_text_formatter/reference.xml index a98b3d8..b7ae62f 100644 --- a/test/external_text_formatter/reference.xml +++ b/test/external_text_formatter/reference.xml @@ -4,7 +4,7 @@ <p> <strong>Lorem ipsum</strong> dolor sit amet, <em>consectetur</em> adipisicing elit, sed do <code>eiusmod</code> tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p> <blockquote> - <p>Duis aute irure dolor in reprehenderit in voluptate +<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p> </blockquote> <p>Excepteur sint <strong>occaecat</strong> cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p> diff --git a/test/external_text_formatter/transformation.xsl b/test/external_text_formatter/transformation.xsl index aa9a300..c6f11fc 100644 --- a/test/external_text_formatter/transformation.xsl +++ b/test/external_text_formatter/transformation.xsl @@ -16,7 +16,7 @@ <xsl:variable name="content" select="InputXSLT:read-file($file)/text()"/> - <xsl:copy-of select="InputXSLT:external-text-formatter( + <xsl:copy-of select="InputXSLT:external-command( $format, $content )"/> |