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 | 
