BPMN-OS
BPMN for optimization and simulation
Loading...
Searching...
No Matches
XMLObject.cpp
Go to the documentation of this file.
1#include "XMLObject.h"
2#include <xercesc/parsers/XercesDOMParser.hpp>
3#include <xercesc/util/BinInputStream.hpp>
4#include <xercesc/sax/InputSource.hpp>
5#include <iostream>
6#include <algorithm>
7
8namespace XML {
9
10// Utility class for parsing directly from an std::istream.
11class IStreamInputSource : public xercesc::InputSource {
12protected:
13 std::istream &is;
14 xercesc::BinInputStream* makeStream() const {
15 return new IStreamBinInputStream(is);
16 }
17
18 class IStreamBinInputStream : public xercesc::BinInputStream {
19 std::istream &is;
20 public:
21 IStreamBinInputStream(std::istream &is) : xercesc::BinInputStream(), is(is) {};
22 XMLFilePos curPos(void) const { return (XMLFilePos)is.tellg(); };
23 XMLSize_t readBytes(XMLByte* const buf, const XMLSize_t max) {
24 is.read((char*)buf, (std::streamsize)max);
25 return (XMLSize_t)is.gcount();
26 };
27 const XMLCh* getContentType() const {
28 //TODO: return application/xml
29 return NULL;
30 };
31 };
32public:
33 IStreamInputSource(std::istream &is) : InputSource(), is(is) {};
34};
35
36std::string transcode(const XMLCh* xmlChStr) {
37 char* cStr = xercesc::XMLString::transcode(xmlChStr);
38 if (!cStr) {
39 throw std::runtime_error("Failed to transcode XML string");
40 }
41 std::string result(cStr);
42 xercesc::XMLString::release(&cStr);
43 return result;
44}
45
46XMLObject* XMLObject::createFromStream(std::istream& xmlStream) {
47 // std::cout << "Create XML object from input stream" << std::endl;
48 xercesc::XMLPlatformUtils::Initialize();
49 std::unique_ptr<xercesc::XercesDOMParser> parser = std::make_unique<xercesc::XercesDOMParser>();
50 parser->setDoNamespaces(true);
51 parser->parse(IStreamInputSource(xmlStream));
52
53 xercesc::DOMDocument* document = parser->getDocument();
54 if (!document) {
55 parser.reset(); // delete unique_ptr to parser before calling Terminate
56 xercesc::XMLPlatformUtils::Terminate();
57 throw std::runtime_error("Failed to parse XML");
58 }
59
60 xercesc::DOMElement* rootElement = document->getDocumentElement();
61 if (!rootElement) {
62 parser.reset(); // delete unique_ptr to parser before calling Terminate
63 xercesc::XMLPlatformUtils::Terminate();
64 throw std::runtime_error("Failed to get root element of XML");
65 }
66
67 std::string rootName = transcode(rootElement->getLocalName());
68 XMLObject* object = createObject(rootElement);
69 parser.reset(); // delete unique_ptr to parser before calling Terminate
70 xercesc::XMLPlatformUtils::Terminate();
71 return object;
72}
73
74XMLObject* XMLObject::createFromString(const std::string& xmlString) {
75 // std::cout << "Create XML object from string" << std::endl;
76 std::istringstream iss(xmlString);
77 return createFromStream(iss);
78}
79
80XMLObject* XMLObject::createFromFile(const std::string& filename) {
81 // std::cout << "Create XML object from file" << std::endl;
82 xercesc::XMLPlatformUtils::Initialize();
83 std::unique_ptr<xercesc::XercesDOMParser> parser = std::make_unique<xercesc::XercesDOMParser>();
84 parser->setDoNamespaces(true);
85 XMLCh* xmlFilename = xercesc::XMLString::transcode(filename.c_str());
86 parser->parse(xmlFilename);
87 xercesc::XMLString::release(&xmlFilename); // Release memory after usage
88
89
90 xercesc::DOMDocument* document = parser->getDocument();
91 if (!document) {
92 parser.reset(); // delete unique_ptr to parser before calling Terminate
93 xercesc::XMLPlatformUtils::Terminate();
94 throw std::runtime_error("Failed to load and parse XML-file");
95 }
96
97 xercesc::DOMElement* rootElement = document->getDocumentElement();
98 if (!rootElement) {
99 parser.reset(); // delete unique_ptr to parser before calling Terminate
100 xercesc::XMLPlatformUtils::Terminate();
101 throw std::runtime_error("Failed to get root element of XML");
102 }
103
104 std::string rootName = transcode(rootElement->getLocalName());
105
106 XMLObject* object = createObject(rootElement);
107 parser.reset(); // delete unique_ptr to parser before calling Terminate
108 xercesc::XMLPlatformUtils::Terminate();
109 return object;
110}
111
112
113XMLObject* XMLObject::createObject(const xercesc::DOMElement* element) {
114 Namespace xmlns = transcode(element->getNamespaceURI());
115 ElementName elementName = transcode(element->getLocalName());
116 if ( auto it = factory.find(xmlns + ":" + elementName); it != factory.end() ) {
117 return it->second(xmlns, elementName, element);
118 }
119 // std::cout << "Unknown element '" << elementName << "' using 'XMLObject' instead" << std::endl;
120 return createInstance<XMLObject>(xmlns, "XMLObject", element);
121}
122
123XMLObject::XMLObject(const Namespace& xmlns, const ClassName& className, const xercesc::DOMElement* element, const Attributes& defaultAttributes) : xmlns(xmlns), className(className) {
124
125 prefix = transcode(element->getPrefix());
126 elementName = transcode(element->getLocalName());
127
128 // set attributes
129 xercesc::DOMNamedNodeMap* elementAttributes = element->getAttributes();
130 for (XMLSize_t i = 0; i < elementAttributes->getLength(); i++) {
131 xercesc::DOMNode* item = elementAttributes->item(i);
132
133 AttributeName attributeName = transcode(item->getLocalName());
134 // get namespace from atrribute or parent element
135 Namespace attributeXmlns = item->getNamespaceURI() ? transcode(item->getNamespaceURI()) : xmlns;
136 Namespace attributePrefix = item->getPrefix() ? transcode(item->getPrefix()) : "";
137 Value attributeValue(transcode(item->getNodeValue()));
138 attributes.push_back( { attributeXmlns, attributePrefix, attributeName, attributeValue } );
139 }
140
141 // add defaults for missing attributes
142 for ( auto& defaultAttribute : defaultAttributes ) {
143 if ( !getOptionalAttributeByName(defaultAttribute.name) ) {
144 attributes.push_back(defaultAttribute);
145 }
146 }
147
148 // set children
149 for (xercesc::DOMElement *childElement = element->getFirstElementChild(); childElement; childElement = childElement->getNextElementSibling()) {
150 children.push_back(std::unique_ptr<XMLObject>(createObject(childElement)));
151 }
152
153 if ( children.empty() ) {
154 textContent = transcode(element->getTextContent());
155 }
156}
157
158
160 for ( auto& child : children ) {
161 if ( child->elementName == elementName ) {
162 return *child;
163 }
164 }
165 throw std::runtime_error("Failed to get required child of element '" + elementName + "'");
166}
167
168std::optional< std::reference_wrapper<XMLObject> > XMLObject::getOptionalChildByName(const ElementName& elementName) {
169 for ( auto& child : children ) {
170 if ( child->elementName == elementName ) {
171 return *child;
172 }
173 }
174 return std::nullopt;
175}
176
177std::vector< std::reference_wrapper<XMLObject> > XMLObject::getChildrenByName(const ElementName& elementName) {
178 std::vector< std::reference_wrapper<XMLObject> > result;
179 for ( auto& child : children ) {
180 if ( child->elementName == elementName ) {
181 result.push_back(*child);
182 }
183 }
184 return result;
185}
186
188 auto it = std::find_if(attributes.begin(), attributes.end(),
189 [attributeName](Attribute& attribute) { return attribute.name == attributeName; }
190 );
191 if (it != attributes.end()) {
192 return *it;
193 }
194 throw std::runtime_error("Failed to get required attribute '" + attributeName + "' of element '" + elementName + "'");
195}
196
197std::optional< std::reference_wrapper<Attribute> > XMLObject::getOptionalAttributeByName(const AttributeName& attributeName) {
198 auto it = std::find_if(attributes.begin(), attributes.end(),
199 [attributeName](Attribute& attribute) { return attribute.name == attributeName; }
200 );
201 if (it != attributes.end()) {
202 return *it;
203 }
204 return std::nullopt;
205}
206
207std::string XMLObject::stringify() const {
208 std::string xmlString = std::string("<") + (!prefix.empty() ? prefix + ":" : "") + elementName;
209 for ( auto& attribute : attributes ) {
210 xmlString += std::string(" ") + (!attribute.prefix.empty() ? attribute.prefix + ":" : "") + attribute.name + "=\"" + attribute.value.value +"\"";
211 }
212 xmlString += ">";
213
214 for ( auto& child : children ) {
215 xmlString += child->stringify();
216 }
217 xmlString += textContent;
218 xmlString += std::string("</") + (!prefix.empty() ? prefix + ":" : "") + elementName + ">";
219 return xmlString;
220}
221
222std::string XMLObject::format(std::string indentation, unsigned int depth) const {
223 // lambda to repeat indentation n times
224 auto indent = [&indentation](unsigned int n) -> std::string {
225 std::string result;
226 for (unsigned int i = 0; i < n; ++i) {
227 result += indentation;
228 }
229 return result;
230 };
231
232 std::string xmlString = indent(depth) + std::string("<") + (!prefix.empty() ? prefix + ":" : "") + elementName;
233 for ( auto& attribute : attributes ) {
234 xmlString += std::string(" ") + (!attribute.prefix.empty() ? attribute.prefix + ":" : "") + attribute.name + "=\"" + attribute.value.value +"\"";
235 }
236 xmlString += ">\n";
237
238 for ( auto& child : children ) {
239 xmlString += child->format(indentation, depth+1);
240 }
241 xmlString += textContent;
242 if ( !textContent.empty() && !textContent.ends_with("\n") ) {
243 xmlString += "\n";
244 }
245 xmlString += indent(depth) + std::string("</") + (!prefix.empty() ? prefix + ":" : "") + elementName + ">\n";
246 return xmlString;
247}
248
249std::ostream& operator<< (std::ostream& os, const XMLObject* obj) {
250 os << obj->stringify();
251 return os;
252}
253
254std::ostream& operator<< (std::ostream& os, const XMLObject& obj) {
255 os << obj.stringify();
256 return os;
257}
258
259} // end namespace XML
260
A class representing a node in an XML-tree.
Definition XMLObject.h:115
Attributes attributes
Definition bpmn++.h:250
static XMLObject * createFromFile(const std::string &filename)
Create an XMLObject from an XML file.
Definition XMLObject.cpp:80
static XMLObject * createFromString(const std::string &xmlString)
Create an XMLObject from a string representation of XML.
Definition XMLObject.cpp:74
static XMLObject * createObject(const xercesc::DOMElement *element)
std::optional< std::reference_wrapper< Attribute > > getOptionalAttributeByName(const AttributeName &attributeName)
Get an optional attribute with the specified attribute name.
ElementName elementName
Definition bpmn++.h:246
std::string format(std::string indentation="\t", unsigned int depth=0) const
Creates formated string representing the XMLObject including its children.
Children children
Child nodes of the XML element.
Definition bpmn++.h:249
Namespace prefix
Definition bpmn++.h:245
static Factory factory
Definition bpmn++.h:156
XMLObject & getRequiredChildByName(const ElementName &elementName)
Get a required child with the specified element name.
TextContent textContent
Textual content of XML element without children.
Definition bpmn++.h:248
std::string stringify() const
Convert the XMLObject and its children to a string representation.
std::vector< std::reference_wrapper< XMLObject > > getChildrenByName(const ElementName &elementName)
Get all children with the specified element name.
XMLObject(const Namespace &xmlns, const ClassName &className, const xercesc::DOMElement *element, const Attributes &defaultAttributes)
friend XMLObject * createInstance(const Namespace &xmlns, const ClassName &className, const xercesc::DOMElement *element)
Template function used to store in factory.
Definition bpmn++.h:85
static XMLObject * createFromStream(std::istream &xmlStream)
Create an XMLObject from the input stream.
Definition XMLObject.cpp:46
std::optional< std::reference_wrapper< XMLObject > > getOptionalChildByName(const ElementName &elementName)
Get the optional child with the specified element name.
Attribute & getRequiredAttributeByName(const AttributeName &attributeName)
Get a required attribute with the specified attribute name.
Namespace xmlns
Definition bpmn++.h:243
The XML namespace contains classes representing XML-nodes defined in given XML-schema(s).
Definition bpmn++.h:18
std::string ElementName
Definition bpmn++.h:23
std::string Namespace
Definition bpmn++.h:25
std::ostream & operator<<(std::ostream &os, const XMLObject *obj)
Allows printing of stringified XML object.
std::string ClassName
Definition bpmn++.h:22
std::vector< Attribute > Attributes
Definition bpmn++.h:81
std::string AttributeName
Definition bpmn++.h:26
std::string transcode(const XMLCh *xmlChStr)
Definition XMLObject.cpp:36
A struct representing an attribute of an XML-node.
Definition XMLObject.h:73
A struct representing the value of an XML-node attribute.
Definition XMLObject.h:48