aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Kummerlaender2014-07-12 16:15:42 +0200
committerAdrian Kummerlaender2014-07-12 16:15:42 +0200
commit086779c6d3d40f244b6aafd6d402fd29b921a735 (patch)
treec606a54c92f9b638797a95437adfe0a6fee05030
parent141725d681dd69f77e993c3d59d613d1ad7014f9 (diff)
downloadInputXSLT-086779c6d3d40f244b6aafd6d402fd29b921a735.tar
InputXSLT-086779c6d3d40f244b6aafd6d402fd29b921a735.tar.gz
InputXSLT-086779c6d3d40f244b6aafd6d402fd29b921a735.tar.bz2
InputXSLT-086779c6d3d40f244b6aafd6d402fd29b921a735.tar.lz
InputXSLT-086779c6d3d40f244b6aafd6d402fd29b921a735.tar.xz
InputXSLT-086779c6d3d40f244b6aafd6d402fd29b921a735.tar.zst
InputXSLT-086779c6d3d40f244b6aafd6d402fd29b921a735.zip
Implemented external "generate" function
* this function essentially provides the same functionality as FunctionTransform with the addition of directly committing the result to the filesystem ** this is needed if one wants to generate doctype-containing transformations from inside a transformation as "write-file" is not able to infer the doctype of a given xalan::XalanNode pointer ** this is a integral limitation of (at least) XSLT 1.0 as implemented in Apache Xalan *** a document can of course only have a single document type *** e.g. we can not include a doctype node in the result tree of FunctionTransform * implemented test case for FunctionGenerate * transformation "test.xsl" is shared between the FunctionTransform and FunctionGenerate test cases * modified README.md accordingly
-rw-r--r--CMakeLists.txt1
-rw-r--r--README.md2
-rw-r--r--src/function/base.h2
-rw-r--r--src/function/generate.cc71
-rw-r--r--src/function/generate.h32
-rw-r--r--src/plattform_guard.cc7
-rw-r--r--test/common/test.xsl (renamed from test/transform/test.xsl)0
-rw-r--r--test/generate/reference.xml10
-rw-r--r--test/generate/transformation.xsl58
-rw-r--r--test/read_directory/reference.xml3
-rw-r--r--test/transform/transformation.xsl2
11 files changed, 186 insertions, 2 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9533c63..331aa2c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -28,6 +28,7 @@ set(
src/function/write_file.cc
src/function/read_directory.cc
src/function/transform.cc
+ src/function/generate.cc
src/function/external_text_formatter.cc
src/support/filesystem_context.cc
src/support/xalan_string.cc
diff --git a/README.md b/README.md
index 6531904..25b77e6 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,7 @@ Contrary to popular opinion I actually like XSLT as a content transformation lan
- external `read-file` function for read-only access to both plain and xml files
- 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 `write-file` function for writing files
@@ -22,6 +23,7 @@ The `test` directory contains black-box test cases for every external function p
- [`InputXSLT:read-file` (xml)](test/read_xml_file/transformation.xsl)
- [`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:write-file`](test/write_file/transformation.xsl)
diff --git a/src/function/base.h b/src/function/base.h
index c3e1fb6..2d1e4c4 100644
--- a/src/function/base.h
+++ b/src/function/base.h
@@ -93,7 +93,7 @@ class FunctionBase : public xalan::Function {
template <std::size_t... Index>
inline xalan::XalanDocument* callConstructDocument(
const XObjectArgVectorType& parameters,
- const xalan::Locator* locator,
+ const xalan::Locator* locator,
Sequence<Index...>
) const {
XObjectValue valueGetter(
diff --git a/src/function/generate.cc b/src/function/generate.cc
new file mode 100644
index 0000000..4ece322
--- /dev/null
+++ b/src/function/generate.cc
@@ -0,0 +1,71 @@
+#include "generate.h"
+
+#include <xalanc/PlatformSupport/XalanOutputStreamPrintWriter.hpp>
+#include <xalanc/PlatformSupport/XalanStdOutputStream.hpp>
+#include <xalanc/XMLSupport/FormatterToXML.hpp>
+
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+
+#include "transformer_facade.h"
+#include "support/xerces_string_guard.h"
+#include "support/dom/result_node_facade.h"
+#include "support/error/error_capacitor.h"
+
+namespace InputXSLT {
+
+DomDocumentCache::document_ptr FunctionGenerate::constructDocument(
+ xalan::XSLTInputSource inputSource,
+ xalan::XSLTInputSource transformationSource,
+ boost::filesystem::path targetPath
+) const {
+ DomDocumentCache::document_ptr domDocument(
+ DomDocumentCache::createDocument("content")
+ );
+
+ ResultNodeFacade result(domDocument.get(), "generation");
+ result.setAttribute("path", targetPath.string());
+
+ boost::filesystem::ofstream file(targetPath);
+
+ if ( file.is_open() ) {
+ TransformerFacade transformer(this->include_resolver_);
+
+ try {
+ xalan::XalanStdOutputStream output(file);
+ xalan::XalanOutputStreamPrintWriter writer(output);
+ xalan::FormatterToXML targetFormatter(writer);
+
+ targetFormatter.setDoIndent(true);
+
+ transformer.generate(
+ inputSource,
+ transformationSource,
+ targetFormatter
+ );
+
+ result.setAttribute("result", "success");
+ }
+ catch (const ErrorCapacitor::exception& exception) {
+ result.setAttribute("result", "error");
+
+ for ( auto&& error : *exception ) {
+ result.setValueNode("error", error);
+ }
+ }
+
+ WarningCapacitor::warning_cache_ptr warnings(
+ transformer.getCachedWarnings()
+ );
+
+ for ( auto&& warning : *warnings ) {
+ result.setValueNode("warning", warning);
+ }
+ } else {
+ result.setAttribute("result", "error");
+ }
+
+ return domDocument;
+}
+
+}
diff --git a/src/function/generate.h b/src/function/generate.h
new file mode 100644
index 0000000..43f5da1
--- /dev/null
+++ b/src/function/generate.h
@@ -0,0 +1,32 @@
+#ifndef INPUTXSLT_SRC_FUNCTION_GENERATE_H_
+#define INPUTXSLT_SRC_FUNCTION_GENERATE_H_
+
+#include <xalanc/XSLT/XSLTInputSource.hpp>
+
+#include "base.h"
+
+namespace InputXSLT {
+
+class FunctionGenerate : public FunctionBase<
+ FunctionGenerate,
+ xalan::XSLTInputSource,
+ xalan::XSLTInputSource,
+ boost::filesystem::path
+> {
+ public:
+ using FunctionBase::FunctionBase;
+
+ protected:
+ friend FunctionBase;
+
+ DomDocumentCache::document_ptr constructDocument(
+ xalan::XSLTInputSource,
+ xalan::XSLTInputSource,
+ boost::filesystem::path
+ ) const;
+
+};
+
+}
+
+#endif // INPUTXSLT_SRC_FUNCTION_GENERATE_H_
diff --git a/src/plattform_guard.cc b/src/plattform_guard.cc
index cc3c9c0..5d19e32 100644
--- a/src/plattform_guard.cc
+++ b/src/plattform_guard.cc
@@ -10,6 +10,7 @@
#include "function/write_file.h"
#include "function/read_directory.h"
#include "function/transform.h"
+#include "function/generate.h"
#include "function/external_text_formatter.h"
namespace InputXSLT {
@@ -49,6 +50,12 @@ PlattformGuard::PlattformGuard(const std::vector<std::string>& path):
xalan::XalanTransformer::installExternalFunctionGlobal(
customNamespace,
+ xalan::XalanDOMString("generate"),
+ InputXSLT::FunctionGenerate(&this->include_resolver_)
+ );
+
+ xalan::XalanTransformer::installExternalFunctionGlobal(
+ customNamespace,
xalan::XalanDOMString("external-text-formatter"),
InputXSLT::FunctionExternalTextFormatter(&this->include_resolver_)
);
diff --git a/test/transform/test.xsl b/test/common/test.xsl
index a9f04a5..a9f04a5 100644
--- a/test/transform/test.xsl
+++ b/test/common/test.xsl
diff --git a/test/generate/reference.xml b/test/generate/reference.xml
new file mode 100644
index 0000000..1c702e8
--- /dev/null
+++ b/test/generate/reference.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<test_case>
+<input_entries>
+<entry>Hello 1</entry>
+<entry>Hello 2</entry>
+<entry>Hello 3</entry>
+<entry>Hello 4</entry>
+</input_entries>
+<parameter_value>42</parameter_value>
+</test_case>
diff --git a/test/generate/transformation.xsl b/test/generate/transformation.xsl
new file mode 100644
index 0000000..6e3d88b
--- /dev/null
+++ b/test/generate/transformation.xsl
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet
+ version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:dyn="http://exslt.org/dynamic"
+ xmlns:xalan="http://xml.apache.org/xalan"
+ xmlns:InputXSLT="function.inputxslt.application"
+ exclude-result-prefixes="dyn xalan InputXSLT"
+>
+
+<xsl:import href="[testcase.xsl]"/>
+
+<xsl:template name="generator">
+ <xsl:param name="input"/>
+ <xsl:param name="transformation"/>
+ <xsl:param name="target"/>
+
+ <xsl:copy-of select="InputXSLT:generate(
+ $input,
+ string($transformation),
+ string($target)
+ )"/>
+</xsl:template>
+
+<xsl:template name="implementation">
+ <xsl:variable name="result">
+ <xsl:call-template name="generator">
+ <xsl:with-param name="input">
+ <test>
+ <entries>
+ <entry>Hello 1</entry>
+ <entry>Hello 2</entry>
+ <entry>Hello 3</entry>
+ <entry>Hello 4</entry>
+ </entries>
+ <parameter>
+ <test>21</test>
+ </parameter>
+ </test>
+ </xsl:with-param>
+ <xsl:with-param name="transformation">[test.xsl]</xsl:with-param>
+ <xsl:with-param name="target">test_actual.xml</xsl:with-param>
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:variable name="generation" select="xalan:nodeset($result)/generation"/>
+
+ <xsl:choose>
+ <xsl:when test="$generation/@result = 'success'">
+ <xsl:copy-of select="InputXSLT:read-file('test_actual.xml')/test_case/transform_test/*"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:copy-of select="$generation/*"/>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/test/read_directory/reference.xml b/test/read_directory/reference.xml
index 7d63a85..d2d9d1b 100644
--- a/test/read_directory/reference.xml
+++ b/test/read_directory/reference.xml
@@ -14,6 +14,9 @@
<name>external_text_formatter</name>
</item>
<item type="directory">
+<name>generate</name>
+</item>
+<item type="directory">
<name>read_directory</name>
</item>
<item type="directory">
diff --git a/test/transform/transformation.xsl b/test/transform/transformation.xsl
index 7cfb8f9..247a4c6 100644
--- a/test/transform/transformation.xsl
+++ b/test/transform/transformation.xsl
@@ -36,7 +36,7 @@
</parameter>
</test>
</xsl:with-param>
- <xsl:with-param name="transformation">test.xsl</xsl:with-param>
+ <xsl:with-param name="transformation">[test.xsl]</xsl:with-param>
</xsl:call-template>
</xsl:variable>