diff options
Diffstat (limited to 'cpp/sca/kernel/xml.hpp')
-rw-r--r-- | cpp/sca/kernel/xml.hpp | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/cpp/sca/kernel/xml.hpp b/cpp/sca/kernel/xml.hpp new file mode 100644 index 0000000000..b4a3b87ad1 --- /dev/null +++ b/cpp/sca/kernel/xml.hpp @@ -0,0 +1,385 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* $Rev$ $Date$ */ + +#ifndef tuscany_xml_hpp +#define tuscany_xml_hpp + +/** + * XML read/write functions. + */ + +#include <libxml/xmlreader.h> +#include <libxml/xmlwriter.h> +#include <libxml/xmlschemas.h> +#include <libxml/globals.h> +#include <iostream> +#include <fstream> +#include <string> +#include "list.hpp" + +namespace tuscany { + +/** + * Encapsulates a libxml2 xmlTextReader and its state. + */ +class XmlReader { +public: + enum TokenType { + None = 0, Element = 1, Attribute = 2, EndElement = 15, Identifier = 100, Text = 101, End = 103 + }; + + explicit XmlReader(xmlTextReaderPtr xml) : xml(xml), tokenType(None) { + xmlTextReaderSetParserProp(xml, XML_PARSER_DEFAULTATTRS, 1); + xmlTextReaderSetParserProp(xml, XML_PARSER_SUBST_ENTITIES, 1); + } + + ~XmlReader() { + xmlFreeTextReader(xml); + } + + /** + * Read the next token and return its type. + */ + int read() { + if (tokenType == End) + return tokenType; + if (tokenType == Element) { + isEmptyElement = xmlTextReaderIsEmptyElement(xml); + hasValue = xmlTextReaderHasValue(xml); + hasAttributes = xmlTextReaderHasAttributes(xml); + return tokenType = Identifier; + } + if (hasValue && tokenType == Identifier) + return tokenType = Text; + if (hasAttributes && (tokenType == Identifier || tokenType == Text) && xmlTextReaderMoveToFirstAttribute(xml) == 1) + return tokenType = Attribute; + if (tokenType == Attribute && xmlTextReaderMoveToNextAttribute(xml) == 1) + return tokenType = Attribute; + if (isEmptyElement && (tokenType == Identifier || tokenType == Text || tokenType == Attribute)) + return tokenType = EndElement; + if (!xmlTextReaderRead(xml)) + return tokenType = End; + return tokenType = xmlTextReaderNodeType(xml); + } + + operator xmlTextReaderPtr() const { + return xml; + } + +private: + const xmlTextReaderPtr xml; + int tokenType; + bool isEmptyElement; + bool hasValue; + bool hasAttributes; +}; + +/** + * Constants used to tag XML tokens. + */ +const value endElement("<"); +const value startElement(">"); +const value attribute("attribute"); +const value element("element"); + +/** + * Read an XML identifier. + */ +const value readIdentifier(XmlReader& reader) { + const char* name = (const char*)xmlTextReaderConstName(reader); + return value(name); +} + +/** + * Read XML text. + */ +const value readText(XmlReader& reader) { + const char *val = (const char*)xmlTextReaderConstValue(reader); + return value(std::string(val)); +} + +/** + * Read an XML attribute. + */ +const value readAttribute(XmlReader& reader) { + const char *name = (const char*)xmlTextReaderConstName(reader); + const char *val = (const char*)xmlTextReaderConstValue(reader); + return value(makeList(attribute, value(name), value(std::string(val)))); +} + +/** + * Read an XML token. + */ +const value readToken(XmlReader& reader) { + const int tokenType = reader.read(); + if (tokenType == XmlReader::End) + return value(); + if (tokenType == XmlReader::Element) + return startElement; + if (tokenType == XmlReader::Identifier) + return readIdentifier(reader); + if (tokenType == XmlReader::Attribute) + return readAttribute(reader); + if (tokenType == XmlReader::Text) + return readText(reader); + if (tokenType == XmlReader::EndElement) + return endElement; + return readToken(reader); +} + +/** + * Read a list of XML tokens. + */ +const list<value> readList(const list<value>& listSoFar, XmlReader& reader) { + const value token = readToken(reader); + if(isNil(token) || endElement == token) + return reverse(listSoFar); + if(startElement == token) + return readList(cons(value(readList(makeList(element), reader)), listSoFar), reader); + return readList(cons(token, listSoFar), reader); +} + +/** + * Read an XML document from a libxml2 XML reader. + */ +const list<value> read(XmlReader& reader) { + value nextToken = readToken(reader); + if (startElement == nextToken) + return makeList(value(readList(makeList(element), reader))); + return list<value>(); +} + +/** + * Callback function called by libxml2 to read the XML input stream. + */ +int readCallback(void *context, char* buffer, int len) { + std::istream* is = static_cast<std::istream*>(context); + is->read(buffer, len); + if (!is->eof() && (is->fail() || is->bad())) + return -1; + const int n = is->gcount(); + return n; +} + +/** + * Read an XML document from an input stream. + */ +const list<value> readXML(std::istream& is) { + xmlTextReaderPtr xml = xmlReaderForIO(readCallback, NULL, &is, NULL, NULL, XML_PARSE_NONET); + if (xml == NULL) + return list<value>(); + XmlReader reader(xml); + return read(reader); +} + +/** + * Callback function called by libxml2 to read the XML file input stream. + */ +int readFileCallback(void *context, char* buffer, int len) { + std::ifstream* is = static_cast<std::ifstream*>(context); + is->read(buffer, len); + if (is->fail() || is->bad()) + return -1; + return is->gcount(); +} + +/** + * Callback function called by libxml2 to close the XML file input stream. + */ +int readCloseFileCallback(void *context) { + std::ifstream* fis = static_cast<std::ifstream*>(context); + fis->close(); + return 0; +} + +/** + * Read an XML document from a file input stream. + */ +const list<value> readXML(std::ifstream& is) { + xmlTextReaderPtr xml = xmlReaderForIO(readFileCallback, readCloseFileCallback, &is, NULL, NULL, XML_PARSE_NONET); + if (xml == NULL) + return list<value>(); + XmlReader reader(xml); + return read(reader); +} + +/** + * Returns true if a value is an XML attribute. + */ +const bool isAttribute(const list<value>& l) { + return !isNil(l) && car(l) == attribute; +} + +/** + * Returns the name of an XML attribute. + */ +const std::string attributeName(const list<value>& l) { + return cadr(l); +} + +/** + * Returns the text value of an XML attribute. + */ +const std::string attributeText(const list<value>& l) { + return caddr(l); +} + +/** + * Returns true if a value is an XML element. + */ +const bool isElement(const list<value>& l) { + return !isNil(l) && car(l) == element; +} + +/** + * Returns the name of an XML element. + */ +const std::string elementName(const list<value>& l) { + return cadr(l); +} + +/** + * Returns true if an XML element contains text content. + */ +const bool elementHasText(const list<value>& l) { + if (isNil(cddr(l))) + return false; + return isString(caddr(l)); +} + +/** + * Returns the text content of an XML element. + */ +const std::string elementText(const list<value>& l) { + return caddr(l); +} + +/** + * Returns the children of an XML element. + */ +const list<value> elementChildren(const list<value>& l) { + return cddr(l); +} + +/** + * Default encoding used to write XML documents. + */ +const char* encoding = "UTF-8"; + +/** + * Write a list of XML element or attribute tokens. + */ +const bool writeList(const list<value>& l, const xmlTextWriterPtr xml) { + if (isNil(l)) + return true; + + // Write an attribute + const list<value> token(car(l)); + if (isAttribute(token)) { + if (xmlTextWriterWriteAttribute(xml, (const xmlChar*)attributeName(token).c_str(), (const xmlChar*)attributeText(token).c_str()) < 0) + return false; + + } else if (isElement(token)) { + + // Write an element + if (xmlTextWriterStartElement(xml, (const xmlChar*)elementName(token).c_str()) < 0) + return false; + if (elementHasText(token) && xmlTextWriterWriteString(xml, (const xmlChar*)elementText(token).c_str()) < 0) + return false; + + // Write its children + writeList(elementChildren(token), xml); + + if (xmlTextWriterEndElement(xml) < 0) + return false; + } + + // Go on + return writeList(cdr(l), xml); +} + +/** + * Write an XML document to a libxml2 XML writer. + */ +const bool write(const list<value>& l, const xmlTextWriterPtr xml) { + if (xmlTextWriterStartDocument(xml, NULL, encoding, NULL) < 0) + return false; + writeList(l, xml); + if (xmlTextWriterEndDocument(xml) < 0) + return false; + return true; +} + +/** + * Callback function called by libxml2 to write to the XML output stream. + */ +int writeCallback(void *context, const char* buffer, int len) { + std::ostream* os = static_cast<std::ostream*>(context); + os->write(buffer, len); + if (os->fail() || os->bad()) + return -1; + return len; +} + +/** + * Write an XML document to an output stream. + */ +const bool writeXML(const list<value>& l, std::ostream& os) { + xmlOutputBufferPtr out = xmlOutputBufferCreateIO(writeCallback, NULL, &os, NULL); + xmlTextWriterPtr xml = xmlNewTextWriter(out); + if (xml == NULL) + return false; + return write(l, xml); +} + +/** + * Callback function called by libxml2 to write to the XML file output stream. + */ +int writeFileCallback(void *context, const char* buffer, int len) { + std::ofstream* os = static_cast<std::ofstream*>(context); + os->write(buffer, len); + if (os->fail() || os->bad()) + return -1; + return len; +} + +/** + * Callback function called by libxml2 to close the XML file output stream. + */ +int writeCloseFileCallback(void *context) { + std::ofstream* fos = static_cast<std::ofstream*>(context); + fos->close(); + return 0; +} + +/** + * Write an XML document to a file output stream. + */ +const bool writeXML(const list<value>& l, std::ofstream& os) { + xmlOutputBufferPtr out = xmlOutputBufferCreateIO(writeFileCallback, writeCloseFileCallback, &os, NULL); + xmlTextWriterPtr xml = xmlNewTextWriter(out); + if (xml == NULL) + return false; + return write(l, xml); +} + +} +#endif /* tuscany_xml_hpp */ |