diff options
author | Benjamin Paassen <bpaassen@techfak.uni-bielefeld.de> | 2015-02-14 00:09:44 +0100 |
---|---|---|
committer | Benjamin Paassen <bpaassen@techfak.uni-bielefeld.de> | 2015-02-14 00:09:44 +0100 |
commit | b708dd4cce828c1089a18fefcc22804f7cdad908 (patch) | |
tree | 61532d98c7c293cc2b56faac7cbfb0f4778b6f75 | |
parent | f3e4071bce35a2d6612a8b065b0166bbc2a4935f (diff) |
added first version of XML output.
-rw-r--r-- | CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/cli/Main.cpp | 71 | ||||
-rw-r--r-- | src/plugins/xml/XmlOutput.cpp | 116 | ||||
-rw-r--r-- | src/plugins/xml/XmlOutput.hpp | 67 |
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 |