aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Kummerlaender2014-08-16 23:30:36 +0200
committerAdrian Kummerlaender2014-08-16 23:30:36 +0200
commitf6ff54c492df81018cf48da039ee681508f88e46 (patch)
tree0659e0f5bf4529b8c83bebc87119607638f98b7f
parent7f6611cded8c1591f1aa1a4c7d70505cb21e7967 (diff)
downloadInputXSLT-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.txt2
-rw-r--r--README.md4
-rw-r--r--ixslt.cc4
-rw-r--r--src/function/base.h27
-rw-r--r--src/function/external_command.cc (renamed from src/function/external_text_formatter.cc)30
-rw-r--r--src/function/external_command.h31
-rw-r--r--src/function/external_text_formatter.h30
-rw-r--r--src/platform_guard.cc6
-rw-r--r--src/support/filesystem_context.h2
-rw-r--r--src/support/include_entity_resolver.cc2
-rw-r--r--src/support/include_entity_resolver.h2
-rw-r--r--src/support/type/filter.h24
-rw-r--r--src/support/type/xobject_value.cc13
-rw-r--r--test/external_text_formatter/reference.xml2
-rw-r--r--test/external_text_formatter/transformation.xsl2
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
diff --git a/README.md b/README.md
index 8629b9a..0593bb5 100644
--- a/README.md
+++ b/README.md
@@ -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).
diff --git a/ixslt.cc b/ixslt.cc
index 23dc9ca..ff5de25 100644
--- a/ixslt.cc
+++ b/ixslt.cc
@@ -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
)"/>