Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
berryXMLMemento.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 BlueBerry Platform
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
17 #include "berryXMLMemento.h"
18 
19 #include "internal/berryWorkbenchPlugin.h"
20 
21 #include <Poco/NumberParser.h>
22 #include <Poco/NumberFormatter.h>
23 #include <Poco/DOM/NodeList.h>
24 #include <Poco/XML/NamePool.h>
25 #include <Poco/DOM/NamedNodeMap.h>
26 #include <Poco/DOM/Text.h>
27 #include <Poco/DOM/Attr.h>
28 #include <Poco/DOM/DOMWriter.h>
29 #include <Poco/DOM/DOMParser.h>
30 #include <Poco/DOM/DOMBuilder.h>
31 #include <Poco/SAX/InputSource.h>
32 #include <Poco/SAX/SAXException.h>
33 
34 #include <limits>
35 
36 const QString EMPTY_STRING;
37 
38 berry::XMLMemento::XMLMemento(Poco::XML::Document* document,
39  Poco::XML::Element* elem) :
40  factory(document), element(elem)
41 {
42  factory->duplicate();
43  element->duplicate();
44 }
45 
47 {
48  element->release();
49  factory->release();
50 }
51 
54 {
55  return CreateReadRoot(reader, "");
56 }
57 
59  berry::XMLMemento::XMLByteInputStream& reader, const QString& baseDir)
60 {
61  QString errorMessage;
62  Poco::Exception exception("");
63 
64  try
65  {
66  Poco::XML::DOMParser parser;
67  Poco::XML::InputSource source(reader);
68 
69  source.setSystemId(baseDir.toStdString());
70  Poco::XML::Document* doc = parser.parse(&source);
71 
72  Poco::XML::Element* elem = doc->documentElement();
73 
74  XMLMemento::Pointer memento(new XMLMemento(doc, elem));
75 
76  doc->release();
77 
78  return memento;
79  }
80  catch (Poco::XML::SAXParseException& e)
81  {
82  errorMessage = QString("Could not parse content of XML file: ") + QString::fromStdString(e.displayText());
83  }
84 
85  QString problemText = QString::fromStdString(exception.message());
86  if (problemText.isEmpty())
87  {
88  problemText = errorMessage.isEmpty() ? "Could not find root element node of XML file." : errorMessage;
89  }
90  throw WorkbenchException(problemText);
91 
92 }
93 
95  const QString& type)
96 {
97  // TODO
98  // try{
99  auto doc = new Poco::XML::Document();
100  Poco::XML::Element* elem = doc->createElement(type.toStdString());
101  doc->appendChild(elem)->release();
102 
103  XMLMemento::Pointer memento(new XMLMemento(doc, elem));
104  doc->release();
105  return memento;
106  //}catch() //TODO: look for poco exceptions
107  //{
108  //}
109 }
110 
112  const QString& type)
113 {
114  Poco::XML::Element* child = factory->createElement(type.toStdString());
115  element->appendChild(child)->release();
116  IMemento::Pointer xmlChild(new XMLMemento(factory,child));
117  return xmlChild;
118 }
119 
121  const QString& type, const QString& id)
122 {
123  Poco::XML::Element* child = factory->createElement(type.toStdString());
124  child->setAttribute(TAG_ID.toStdString(), id.toStdString());
125  element->appendChild(child)->release();
126  IMemento::Pointer xmlChild(new XMLMemento(factory,child));
127  return xmlChild;
128 }
129 
131 {
132  //TODO check any casting errors
133  Poco::XML::Element* elem = child.Cast<berry::XMLMemento> ()->GetElement();
134  Poco::XML::Element* newElement =
135  dynamic_cast<Poco::XML::Element*> (factory->importNode(elem, true));
136  element->appendChild(newElement)->release();
137  IMemento::Pointer xmlCopy(new XMLMemento(factory, newElement));
138  return xmlCopy;
139 
140 }
141 
143 {
144  // Get the nodes.
146  Poco::XML::Element* child = element->getChildElement(type.toStdString()); // Find the first node which is a child of this node
147  if (child)
148  {
149  memento = new berry::XMLMemento(factory, child);
150  return memento;
151  }
152  // A child was not found.
153  return memento;
154 }
155 
156 QList<berry::IMemento::Pointer> berry::XMLMemento::GetChildren(
157  const QString& type) const
158 {
159  QList<IMemento::Pointer> mementos;
160  Poco::XML::NodeList* elementList = element->getElementsByTagName(type.toStdString());
161  for (unsigned long i = 0; i < elementList->length(); i++)
162  {
163  Poco::XML::Element* elem =
164  dynamic_cast<Poco::XML::Element*> (elementList->item(i));
165  IMemento::Pointer child(new berry::XMLMemento(factory, elem));
166  mementos << child;
167  }
168  elementList->release();
169 
170  return mementos;
171 }
172 
173 bool berry::XMLMemento::GetFloat(const QString& key, double& value) const
174 {
175  if (!element->hasAttribute(key.toStdString())) return false;
176 
177  const std::string& attr = element->getAttribute(key.toStdString());
178 
179  try
180  {
181  value = Poco::NumberParser::parseFloat(attr);
182  } catch (const Poco::SyntaxException& /*e*/)
183  {
184  std::string _qnan = Poco::NumberFormatter::format(std::numeric_limits<double>::quiet_NaN());
185  if (_qnan == attr)
186  {
187  value = std::numeric_limits<double>::quiet_NaN();
188  return true;
189  }
190 
191  std::string _inf = Poco::NumberFormatter::format(std::numeric_limits<double>::infinity());
192  if (_inf == attr)
193  {
194  value = std::numeric_limits<double>::infinity();
195  return true;
196  }
197 
198  WorkbenchPlugin::Log("Memento problem - invalid float for key: " + key
199  + " value: " + QString::fromStdString(attr));
200  return false;
201  }
202 
203  return true;
204 }
205 
207 {
208  return QString::fromStdString(element->nodeName());
209 }
210 
212 {
213  //TODO: make error handling!
214  return QString::fromStdString(element->getAttribute(TAG_ID.toStdString()));
215 }
216 
217 bool berry::XMLMemento::GetInteger(const QString& key, int& value) const
218 {
219  if (!element->hasAttribute(key.toStdString())) return false;
220 
221  const std::string& attr = element->getAttribute(key.toStdString());
222 
223  try
224  {
225  value = Poco::NumberParser::parse(attr);
226  }
227  catch (const Poco::SyntaxException& /*e*/)
228  {
229  WorkbenchPlugin::Log("Memento problem - invalid integer for key: " + key
230  + " value: " + QString::fromStdString(attr));
231  return false;
232  }
233 
234  return true;
235 }
236 
237 bool berry::XMLMemento::GetBoolean(const QString& key, bool& value) const
238 {
239  const std::string& attr = element->getAttribute(key.toStdString());
240  if (attr.empty())
241  return false;
242  else if (attr == "true")
243  {
244  value = true;
245  return true;
246  }
247  else
248  {
249  value = false;
250  return true;
251  }
252 }
253 
254 bool berry::XMLMemento::GetString(const QString& key, QString& value) const
255 {
256  QString v = QString::fromStdString(element->getAttribute(key.toStdString()));
257  if (v.isEmpty())
258  return false;
259 
260  value = v;
261  return true;
262 }
263 
265 {
266  Poco::XML::Text* textNode = GetTextNode();
267 
268  if (textNode != nullptr)
269  {
270  return QString::fromStdString(textNode->getData());
271  }
272 
273  return EMPTY_STRING;
274 }
275 
277 {
278  QList<QString> values;
279  Poco::XML::NamedNodeMap* nnMap = element->attributes();
280 
281  values.reserve(nnMap->length());
282 
283  for (unsigned long i = 0; i < nnMap->length(); i++)
284  {
285  values[i] = QString::fromStdString(nnMap->item(i)->nodeName()); //TODO check if right
286  }
287 
288  return values;
289 }
290 
291 Poco::XML::Text* berry::XMLMemento::GetTextNode() const
292 {
293 
294  //Get the nodes
295  Poco::XML::NodeList* nodes = element->childNodes();
296 
297  unsigned long size = nodes->length();
298 
299  if (size == 0)
300  return nullptr;
301 
302  //Search for the text node
303  for (unsigned long index = 0; index < size; index++)
304  {
305  if (nodes->item(index)->nodeType() == Poco::XML::Node::TEXT_NODE)
306  {
307  return dynamic_cast<Poco::XML::Text*> (nodes->item(index));
308  }
309  }
310 
311  // a Text node was not found
312  return nullptr;
313 
314 }
315 
316 void berry::XMLMemento::PutElement(Poco::XML::Element* element, bool copyText)
317 {
318  Poco::XML::NamedNodeMap* nodeMap = element->attributes();
319  unsigned long size = nodeMap->length();
320 
321  for (unsigned long index = 0; index < size; index++)
322  {
323  Poco::XML::Node* node = nodeMap->item(index);
324  Poco::XML::Attr* attr = dynamic_cast<Poco::XML::Attr*> (node);
325  PutString(QString::fromStdString(attr->nodeName()),
326  QString::fromStdString(attr->nodeValue()));
327  }
328  nodeMap->release();
329 
330  bool needToCopyText = copyText;
331  Poco::XML::Node* child = element->firstChild();
332  while (child)
333  {
334  unsigned short nodeType = child->nodeType();
335 
336  switch (nodeType)
337  {
338  case Poco::XML::Node::ELEMENT_NODE:
339  {
340  Poco::XML::Element* elem = dynamic_cast<Poco::XML::Element*> (child);
341  XMLMemento::Pointer child = CreateChild(QString::fromStdString(elem->nodeName())).Cast<
342  berry::XMLMemento> ();
343  child->PutElement(elem, true);
344  }
345  break;
346  case Poco::XML::Node::TEXT_NODE:
347  if (needToCopyText)
348  {
349  Poco::XML::Text* text = dynamic_cast<Poco::XML::Text*> (child);
350  PutTextData(QString::fromStdString(text->getData()));
351  needToCopyText = false;
352  }
353  break;
354 
355  default:
356  break;
357  }
358 
359  child = child->nextSibling();
360  }
361 }
362 
363 void berry::XMLMemento::PutFloat(const QString& key, double value)
364 {
365  std::string xmlValue = Poco::NumberFormatter::format(value);
366  element->setAttribute(key.toStdString(), xmlValue);
367 }
368 
369 void berry::XMLMemento::PutInteger(const QString& key, int value)
370 {
371  std::string xmlValue = Poco::NumberFormatter::format(value);
372  element->setAttribute(key.toStdString(), xmlValue);
373 }
374 
376 {
377  // Do not copy the element's top level text node (this would overwrite the existing text).
378  // Text nodes of children are copied.
379  PutElement(memento.Cast<berry::XMLMemento> ()->GetElement(), false);
380 }
381 
382 void berry::XMLMemento::PutString(const QString& key,
383  const QString& value)
384 {
385  element->setAttribute(key.toStdString(), value.toStdString());
386  //if (value == null) {
387  // return;}
388  //element.setAttribute(key, value);
389 }
390 
391 void berry::XMLMemento::PutBoolean(const QString& key, bool value)
392 {
393  if (value)
394  {
395  element->setAttribute(key.toStdString(), "true");
396  }
397  else
398  {
399  element->setAttribute(key.toStdString(), "false");
400  }
401 }
402 
403 void berry::XMLMemento::PutTextData(const QString& data)
404 {
405  Poco::XML::Text* textNode = GetTextNode();
406  if (textNode == nullptr)
407  {
408  textNode = factory->createTextNode(data.toStdString());
409  element->insertBefore(textNode, element->firstChild())->release();
410  }
411  else
412  {
413  textNode->setData(data.toStdString());
414  }
415 }
416 
417 void berry::XMLMemento::Save(berry::XMLMemento::XMLByteOutputStream& writer)
418 {
419  if (writer.good())
420  {
421  Poco::XML::DOMWriter out;
422  out.setOptions(3); //write declaration and pretty print
423  out.writeNode(writer, factory);
424  }
425  else
426  {
427  //TODO
428  }
429 }
430 Poco::XML::Element* berry::XMLMemento::GetElement() const
431 {
432  return element;
433 }
434 
virtual void PutString(const QString &key, const QString &value) override
virtual QList< QString > GetAttributeKeys() const override
virtual bool GetInteger(const QString &key, int &value) const override
virtual void PutBoolean(const QString &key, bool value) override
IMemento::Pointer CopyChild(IMemento::Pointer child)
virtual QList< IMemento::Pointer > GetChildren(const QString &type) const override
virtual QString GetTextData() const override
virtual void PutInteger(const QString &key, int value) override
virtual bool GetFloat(const QString &key, double &value) const override
virtual QString GetType() const override
virtual Poco::XML::Element * GetElement() const
const QString EMPTY_STRING
virtual bool GetString(const QString &key, QString &value) const override
berryObjectMacro(XMLMemento) typedef std typedef std::istream XMLByteInputStream
berry::SmartPointer< Self > Pointer
Definition: berryObject.h:88
static XMLMemento::Pointer CreateReadRoot(berry::XMLMemento::XMLByteInputStream &reader)
virtual void PutTextData(const QString &data) override
virtual IMemento::Pointer CreateChild(const QString &type) override
virtual IMemento::Pointer GetChild(const QString &type) const override
virtual void PutFloat(const QString &key, double value) override
static XMLMemento::Pointer CreateWriteRoot(const QString &type)
virtual QString GetID() const override
void Save(XMLByteOutputStream &writer)
SmartPointer< Other > Cast() const
virtual bool GetBoolean(const QString &key, bool &value) const override
XMLMemento(Poco::XML::Document *document, Poco::XML::Element *elem)
virtual void PutMemento(IMemento::Pointer memento) override