aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Kummerländer2014-05-12 18:49:24 +0200
committerAdrian Kummerländer2014-05-12 18:49:24 +0200
commitc4fcfa9b39d9c29ecbc3ac1c12b7e5b2beb24a6d (patch)
treed76ed8e9934ac6b79aabf76a7f401cfa72d37f7b
parent20fca5978b55606062cdaf4c94dec82f5318a62a (diff)
downloadInputXSLT-c4fcfa9b39d9c29ecbc3ac1c12b7e5b2beb24a6d.tar
InputXSLT-c4fcfa9b39d9c29ecbc3ac1c12b7e5b2beb24a6d.tar.gz
InputXSLT-c4fcfa9b39d9c29ecbc3ac1c12b7e5b2beb24a6d.tar.bz2
InputXSLT-c4fcfa9b39d9c29ecbc3ac1c12b7e5b2beb24a6d.tar.lz
InputXSLT-c4fcfa9b39d9c29ecbc3ac1c12b7e5b2beb24a6d.tar.xz
InputXSLT-c4fcfa9b39d9c29ecbc3ac1c12b7e5b2beb24a6d.tar.zst
InputXSLT-c4fcfa9b39d9c29ecbc3ac1c12b7e5b2beb24a6d.zip
Implemented basic external transform function
* "InputXSLT:transform" expects two input arguments and executes the given transformation into the given target file ** this function respresents a important step in the direction of making it possible to write an actual static site generator on top of InputXSLT using XSLT * added basic "transform" test case * updated README.md to include this new function
-rw-r--r--CMakeLists.txt1
-rw-r--r--README.md1
-rw-r--r--src/function/transform.cc113
-rw-r--r--src/function/transform.h43
-rw-r--r--src/plattform_guard.cc7
-rw-r--r--test/read_directory/reference.xml1
-rw-r--r--test/transform/reference.xml35
-rw-r--r--test/transform/test.xsl24
-rw-r--r--test/transform/transformation.xsl31
9 files changed, 256 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5173ef4..da44f2b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -27,6 +27,7 @@ set(
src/function/read_file.cc
src/function/read_xml_file.cc
src/function/read_directory.cc
+ src/function/transform.cc
src/support/filesystem_context.cc
src/support/stylesheet_parameter_guard.cc
src/support/dom/document_cache.cc
diff --git a/README.md b/README.md
index 5ae65e5..867de8f 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 text files
- 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
## Requirements:
diff --git a/src/function/transform.cc b/src/function/transform.cc
new file mode 100644
index 0000000..9b600d9
--- /dev/null
+++ b/src/function/transform.cc
@@ -0,0 +1,113 @@
+#include "transform.h"
+
+#include <xercesc/dom/DOMDocument.hpp>
+#include <xercesc/dom/DOMImplementation.hpp>
+#include <xercesc/dom/DOMElement.hpp>
+
+#include "transformation_facade.h"
+#include "support/xerces_string_guard.h"
+
+namespace {
+
+using InputXSLT::XercesStringGuard;
+
+xercesc::DOMDocument* constructDocument(
+ const InputXSLT::FilesystemContext&,
+ const boost::filesystem::path& transformationPath,
+ const boost::filesystem::path& targetPath
+) {
+ xercesc::DOMDocument* const domDocument(
+ xercesc::DOMImplementation::getImplementation()->createDocument(
+ nullptr,
+ *XercesStringGuard<XMLCh>("content"),
+ nullptr
+ )
+ );
+
+ xercesc::DOMNode* const rootNode(
+ domDocument->getDocumentElement()
+ );
+
+ InputXSLT::TransformationFacade transformation(
+ transformationPath.string()
+ );
+
+ const int result = transformation.generate(
+ targetPath.string()
+ );
+
+ if ( result == 0 ) {
+ xercesc::DOMElement* const resultNode(
+ domDocument->createElement(*XercesStringGuard<XMLCh>("result"))
+ );
+
+ resultNode->setAttribute(
+ *XercesStringGuard<XMLCh>("name"),
+ *XercesStringGuard<XMLCh>(targetPath.string())
+ );
+
+ rootNode->appendChild(resultNode);
+ } else {
+ xercesc::DOMElement* const resultNode(
+ domDocument->createElement(*XercesStringGuard<XMLCh>("error"))
+ );
+
+ rootNode->appendChild(resultNode);
+ }
+
+ return domDocument;
+}
+
+}
+
+namespace InputXSLT {
+
+FunctionTransform::FunctionTransform():
+ document_cache_(std::make_shared<DomDocumentCache>()) { }
+
+xalan::XObjectPtr FunctionTransform::execute(
+ xalan::XPathExecutionContext& executionContext,
+ xalan::XalanNode*,
+ const xalan::XObjectPtr argument1,
+ const xalan::XObjectPtr argument2,
+ const xalan::Locator* locator
+) const {
+ const FilesystemContext fsContext(locator);
+
+ xalan::XalanDocument* const domDocument(
+ this->document_cache_->create(
+ constructDocument(
+ fsContext,
+ fsContext.resolve(argument1->str()),
+ fsContext.resolve(argument2->str())
+ )
+ )
+ );
+
+ xalan::XPathExecutionContext::BorrowReturnMutableNodeRefList nodeList(
+ executionContext
+ );
+
+ nodeList->addNodes(
+ *domDocument->getDocumentElement()->getChildNodes()
+ );
+
+ return executionContext.getXObjectFactory().createNodeSet(nodeList);
+}
+
+FunctionTransform* FunctionTransform::clone(
+ xalan::MemoryManager& manager) const {
+ return xalan::XalanCopyConstruct(
+ manager,
+ *this
+ );
+}
+
+const xalan::XalanDOMString& FunctionTransform::getError(
+ xalan::XalanDOMString& result) const {
+ result.assign("The function expects two arguments of type string.");
+
+ return result;
+}
+
+}
diff --git a/src/function/transform.h b/src/function/transform.h
new file mode 100644
index 0000000..41bba05
--- /dev/null
+++ b/src/function/transform.h
@@ -0,0 +1,43 @@
+#ifndef INPUTXSLT_SRC_FUNCTION_TRANSFORM_H_
+#define INPUTXSLT_SRC_FUNCTION_TRANSFORM_H_
+
+#include <xalanc/XalanTransformer/XalanTransformer.hpp>
+#include <xalanc/XPath/XObjectFactory.hpp>
+#include <xalanc/XPath/Function.hpp>
+#include <xalanc/XPath/XObject.hpp>
+
+#include <memory>
+
+#include "common.h"
+#include "support/dom/document_cache.h"
+#include "support/filesystem_context.h"
+
+namespace InputXSLT {
+
+class FunctionTransform : public xalan::Function {
+ public:
+ FunctionTransform();
+
+ virtual xalan::XObjectPtr execute(
+ xalan::XPathExecutionContext&,
+ xalan::XalanNode*,
+ const xalan::XObjectPtr,
+ const xalan::XObjectPtr,
+ const xalan::Locator*
+ ) const;
+
+ virtual FunctionTransform* clone(xalan::MemoryManager&) const;
+
+ FunctionTransform& operator=(const FunctionTransform&) = delete;
+ bool operator==(const FunctionTransform&) const = delete;
+
+ private:
+ std::shared_ptr<DomDocumentCache> document_cache_;
+
+ const xalan::XalanDOMString& getError(xalan::XalanDOMString&) const;
+
+};
+
+}
+
+#endif // INPUTXSLT_SRC_FUNCTION_TRANSFORM_H_
diff --git a/src/plattform_guard.cc b/src/plattform_guard.cc
index 2c3cee4..da3b6d7 100644
--- a/src/plattform_guard.cc
+++ b/src/plattform_guard.cc
@@ -9,6 +9,7 @@
#include "function/read_file.h"
#include "function/read_xml_file.h"
#include "function/read_directory.h"
+#include "function/transform.h"
namespace InputXSLT {
@@ -37,6 +38,12 @@ PlattformGuard::PlattformGuard() {
xalan::XalanDOMString("read-directory"),
InputXSLT::FunctionReadDirectory()
);
+
+ xalan::XalanTransformer::installExternalFunctionGlobal(
+ customNamespace,
+ xalan::XalanDOMString("transform"),
+ InputXSLT::FunctionTransform()
+ );
}
PlattformGuard::~PlattformGuard() {
diff --git a/test/read_directory/reference.xml b/test/read_directory/reference.xml
index 76fb84f..fedd903 100644
--- a/test/read_directory/reference.xml
+++ b/test/read_directory/reference.xml
@@ -5,6 +5,7 @@
<item>read_xml_file</item>
<item>common</item>
<item>read_file</item>
+<item>transform</item>
<item>default_params</item>
</function_read_directory>
</test_case>
diff --git a/test/transform/reference.xml b/test/transform/reference.xml
new file mode 100644
index 0000000..37c060e
--- /dev/null
+++ b/test/transform/reference.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<test_case>
+<transform>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
+&lt;xsl:stylesheet
+ version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:InputXSLT="function.inputxslt.application"
+ exclude-result-prefixes="InputXSLT"
+&gt;
+
+&lt;xsl:output
+ method="xml"
+ omit-xml-declaration="no"
+ encoding="UTF-8"
+ indent="yes"
+/&gt;
+
+&lt;xsl:template match="/"&gt;
+&lt;test_case&gt;
+ &lt;transform&gt;
+ &lt;xsl:variable
+ name = "result"
+ select = "InputXSLT:transform('test.xsl', 'test_actual.xml')"
+ /&gt;
+
+ &lt;xsl:value-of select="
+ InputXSLT:read-xml-file('test_actual.xml')/test_case/transform_test
+ "/&gt;
+ &lt;/transform&gt;
+&lt;/test_case&gt;
+&lt;/xsl:template&gt;
+
+&lt;/xsl:stylesheet&gt;
+</transform>
+</test_case>
diff --git a/test/transform/test.xsl b/test/transform/test.xsl
new file mode 100644
index 0000000..40134c4
--- /dev/null
+++ b/test/transform/test.xsl
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet
+ version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:InputXSLT="function.inputxslt.application"
+ exclude-result-prefixes="InputXSLT"
+>
+
+<xsl:output
+ method="xml"
+ omit-xml-declaration="no"
+ encoding="UTF-8"
+ indent="yes"
+/>
+
+<xsl:template match="/">
+<test_case>
+ <transform_test>
+ <xsl:value-of select="InputXSLT:read-file('transformation.xsl')"/>
+ </transform_test>
+</test_case>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/test/transform/transformation.xsl b/test/transform/transformation.xsl
new file mode 100644
index 0000000..9039642
--- /dev/null
+++ b/test/transform/transformation.xsl
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet
+ version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:InputXSLT="function.inputxslt.application"
+ exclude-result-prefixes="InputXSLT"
+>
+
+<xsl:output
+ method="xml"
+ omit-xml-declaration="no"
+ encoding="UTF-8"
+ indent="yes"
+/>
+
+<xsl:template match="/">
+<test_case>
+ <transform>
+ <xsl:variable
+ name = "result"
+ select = "InputXSLT:transform('test.xsl', 'test_actual.xml')"
+ />
+
+ <xsl:value-of select="
+ InputXSLT:read-xml-file('test_actual.xml')/test_case/transform_test
+ "/>
+ </transform>
+</test_case>
+</xsl:template>
+
+</xsl:stylesheet>