summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--src/cli/Main.cpp71
-rw-r--r--src/plugins/xml/XmlOutput.cpp116
-rw-r--r--src/plugins/xml/XmlOutput.hpp67
4 files changed, 231 insertions, 24 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1614457..ab31dab 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -192,6 +192,7 @@ TARGET_LINK_LIBRARIES(ousia_html
)
ADD_LIBRARY(ousia_xml
+ src/plugins/xml/XmlOutput
src/plugins/xml/XmlParser
)
diff --git a/src/cli/Main.cpp b/src/cli/Main.cpp
index 2dbeda8..2786025 100644
--- a/src/cli/Main.cpp
+++ b/src/cli/Main.cpp
@@ -30,6 +30,8 @@
#include <algorithm>
#include <fstream>
#include <iostream>
+#include <ostream>
+#include <set>
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>
@@ -48,6 +50,7 @@
#include <plugins/filesystem/FileLocator.hpp>
#include <plugins/html/DemoOutput.hpp>
#include <plugins/xml/XmlParser.hpp>
+#include <plugins/xml/XmlOutput.hpp>
const size_t ERROR_IN_COMMAND_LINE = 1;
const size_t SUCCESS = 0;
@@ -74,6 +77,20 @@ const char *MSG_COPYING =
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
"GNU General Public License for more details.\n";
+const std::set<std::string> formats{"html", "xml"};
+
+static void createOutput(Handle<Document> doc, std::ostream &out,
+ const std::string &format, Logger &logger)
+{
+ if (format == "html") {
+ html::DemoHTMLTransformer transform;
+ transform.writeHTML(doc, out, true);
+ } else if (format == "xml") {
+ xml::XmlTransformer transform;
+ transform.writeXml(doc, out, logger, true);
+ }
+}
+
int main(int argc, char **argv)
{
// Initialize terminal logger. Only use color if writing to a terminal (tty)
@@ -141,7 +158,7 @@ int main(int argc, char **argv)
if (inputPath == "-") {
logger.error("Currently no reading from std::in is supported!");
return ERROR_IN_COMMAND_LINE;
- } else{
+ } else {
inputPath = fs::canonical(inputPath).string();
}
@@ -155,21 +172,28 @@ int main(int argc, char **argv)
outputPath = outP.string();
std::cout << "Using " << outputPath << " as output path." << std::endl;
}
-
- // TODO: REMOVE diagnostic code.
- std::cout << "input : " << vm["input"].as<std::string>() << std::endl;
- std::cout << "output : " << outputPath << std::endl;
- std::cout << "format : " << vm["format"].as<std::string>() << std::endl;
- if (vm.count("include")) {
- std::vector<std::string> includes =
- vm["include"].as<std::vector<std::string>>();
- std::cout << "includes : ";
- for (auto &i : includes) {
- std::cout << i << ", ";
+ // check format.
+ if (!formats.count(format)) {
+ logger.error("Format must be one of: ");
+ for (auto &f : formats) {
+ logger.error(f);
}
- std::cout << std::endl;
}
+ // TODO: REMOVE diagnostic code.
+ // std::cout << "input : " << vm["input"].as<std::string>() << std::endl;
+ // std::cout << "output : " << outputPath << std::endl;
+ // std::cout << "format : " << vm["format"].as<std::string>() << std::endl;
+ // if (vm.count("include")) {
+ // std::vector<std::string> includes =
+ // vm["include"].as<std::vector<std::string>>();
+ // std::cout << "includes : ";
+ // for (auto &i : includes) {
+ // std::cout << i << ", ";
+ // }
+ // std::cout << std::endl;
+ // }
+
// initialize global instances.
Manager manager;
Registry registry;
@@ -206,21 +230,20 @@ int main(int argc, char **argv)
}
// now all preparation is done and we can parse the input document.
- Rooted<Node> doc = context.import(inputPath, "text/vnd.ousia.oxd", "",
- {&RttiTypes::Document});
- if (logger.hasError() || doc == nullptr) {
+ Rooted<Node> docNode = context.import(inputPath, "text/vnd.ousia.oxd", "",
+ {&RttiTypes::Document});
+ if (logger.hasError() || docNode == nullptr) {
logger.fatalError("Errors occured while parsing the document");
return ERROR_IN_DOCUMENT;
}
-
- // write output.
- html::DemoHTMLTransformer outTransformer;
- if (outputPath == "-") {
- outTransformer.writeHTML(doc.cast<Document>(), std::cout);
+ Rooted<Document> doc = docNode.cast<Document>();
+ // write output
+ if (outputPath != "-") {
+ std::fstream out{outputPath};
+ createOutput(doc, out, format, logger);
} else {
- std::fstream out {outputPath};
- outTransformer.writeHTML(doc.cast<Document>(), out);
+ createOutput(doc, std::cout, format, logger);
}
return SUCCESS;
-}
+} \ No newline at end of file
diff --git a/src/plugins/xml/XmlOutput.cpp b/src/plugins/xml/XmlOutput.cpp
new file mode 100644
index 0000000..00aae04
--- /dev/null
+++ b/src/plugins/xml/XmlOutput.cpp
@@ -0,0 +1,116 @@
+/*
+ Ousía
+ Copyright (C) 2014 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "XmlOutput.hpp"
+
+#include <core/common/Variant.hpp>
+#include <core/common/VariantWriter.hpp>
+
+namespace ousia {
+namespace xml {
+
+void XmlTransformer::writeXml(Handle<Document> doc, std::ostream &out,
+ Logger &logger, bool pretty)
+{
+ Manager &mgr = doc->getManager();
+ // the outermost tag is the document itself.
+ Rooted<Element> document{new Element{mgr, {nullptr}, "document"}};
+ // then write imports for all references domains.
+ for (auto d : doc->getDomains()) {
+ Rooted<Element> import{
+ new Element{mgr,
+ document,
+ "import",
+ {{"rel", "domain"}, {"src", d->getName() + ".oxm"}}}};
+ document->addChild(import);
+ }
+ // transform the root element (and, using recursion, everything below it)
+ Rooted<Element> root =
+ transformStructuredEntity(document, doc->getRoot(), logger, pretty);
+ document->addChild(root);
+ // then serialize.
+ document->serialize(out, "<?xml version=\"1.0\"?>", pretty);
+}
+
+Rooted<Element> XmlTransformer::transformStructuredEntity(
+ Handle<Element> parent, Handle<StructuredEntity> s, Logger &logger,
+ bool pretty)
+{
+ Manager &mgr = parent->getManager();
+ // TODO: Is this the right handling?
+ // copy the attributes.
+ Variant attrs = s->getAttributes();
+ // build them.
+ s->getDescriptor()->getAttributesDescriptor()->build(attrs, logger);
+ // get the array representation.
+ Variant::arrayType attrArr = attrs.asArray();
+ // transform them to string key-value pairs.
+ NodeVector<Attribute> as =
+ s->getDescriptor()->getAttributesDescriptor()->getAttributes();
+ std::map<std::string, std::string> xmlAttrs;
+ for (size_t a = 0; a < as.size(); a++) {
+ xmlAttrs.emplace(as[a]->getName(),
+ VariantWriter::writeJsonToString(attrArr[a], pretty));
+ }
+ // create the XML element itself.
+ Rooted<Element> elem{
+ new Element{mgr, parent, s->getDescriptor()->getName(), xmlAttrs}};
+ // then transform the fields.
+ NodeVector<FieldDescriptor> fieldDescs =
+ s->getDescriptor()->getFieldDescriptors();
+ for (size_t f = 0; f < fieldDescs.size(); f++) {
+ NodeVector<StructureNode> field = s->getField(f);
+ Rooted<FieldDescriptor> fieldDesc = fieldDescs[f];
+ // if this is not the default node create an intermediate node for it.
+ Rooted<Element> par = elem;
+ if (fieldDesc->getFieldType() != FieldDescriptor::FieldType::TREE &&
+ !fieldDesc->isPrimitive()) {
+ par = Rooted<Element>{new Element(mgr, elem, fieldDesc->getName())};
+ elem->addChild(par);
+ }
+ for (auto c : field) {
+ // transform each child.
+ Rooted<Node> child;
+ if (c->isa(&RttiTypes::StructuredEntity)) {
+ child = transformStructuredEntity(
+ par, c.cast<StructuredEntity>(), logger, pretty);
+ } else if (c->isa(&RttiTypes::DocumentPrimitive)) {
+ child = transformPrimitive(par, c.cast<DocumentPrimitive>(),
+ logger, pretty);
+ }
+ // TODO: Handle Anchors
+ if (child != nullptr) {
+ par->addChild(child);
+ }
+ }
+ }
+ return elem;
+}
+Rooted<Text> XmlTransformer::transformPrimitive(Handle<Element> parent,
+ Handle<DocumentPrimitive> p,
+ Logger &logger, bool pretty)
+{
+ Manager &mgr = parent->getManager();
+ // transform the primitive content.
+ std::string textcontent =
+ VariantWriter::writeJsonToString(p->getContent(), pretty);
+ Rooted<Text> text{new Text(mgr, parent, textcontent)};
+ return text;
+}
+}
+} \ No newline at end of file
diff --git a/src/plugins/xml/XmlOutput.hpp b/src/plugins/xml/XmlOutput.hpp
new file mode 100644
index 0000000..51d03f9
--- /dev/null
+++ b/src/plugins/xml/XmlOutput.hpp
@@ -0,0 +1,67 @@
+/*
+ Ousía
+ Copyright (C) 2014 Benjamin Paaßen, Andreas Stöckel
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file XmlOutput.hpp
+ *
+ * This provices an Output generator to serialize any given document to XML.
+ *
+ * @author Benjamin Paaßen (bpaassen@techfak.uni-bielefeld.de)
+ */
+#ifndef _OUSIA_XML_OUTPUT_HPP_
+#define _OUSIA_XML_OUTPUT_HPP_
+
+#include <ostream>
+
+#include <core/model/Document.hpp>
+#include <core/XML.hpp>
+
+namespace ousia {
+namespace xml {
+
+class XmlTransformer {
+private:
+ Rooted<Element> transformStructuredEntity(Handle<Element> parent,
+ Handle<StructuredEntity> s,
+ Logger &logger, bool pretty);
+
+ Rooted<Text> transformPrimitive(Handle<Element> parent,
+ Handle<DocumentPrimitive> p,
+ Logger &logger, bool pretty);
+
+public:
+ /**
+ * This writes an XML serialization of the given document to the given
+ * output stream. The serialization is equivalent to the input XML format,
+ * safe for the domain references. TODO: Can we change this? If so: how?
+ * Note, though, that the serialization will not exploit transparency.
+ * TODO: Can we change that?
+ *
+ * @param doc is some Document.
+ * @param out is the output stream the XML serialization of the document
+ * shall be written to.
+ * @param logger is the logger errors shall be written to.
+ * @param pretty is a flag that manipulates whether newlines and tabs are
+ * used.
+ */
+ void writeXml(Handle<Document> doc, std::ostream &out, Logger &logger,
+ bool pretty);
+};
+}
+}
+#endif \ No newline at end of file