Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
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