Medical Imaging Interaction Toolkit  2018.4.99-c4b6bb11
Medical Imaging Interaction Toolkit
mitkPropertyListSerializer.cpp
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
15 
16 #include <tinyxml.h>
17 
19 #include <itksys/SystemTools.hxx>
20 
21 mitk::PropertyListSerializer::PropertyListSerializer() : m_FilenameHint("unnamed"), m_WorkingDirectory("")
22 {
23 }
24 
26 {
27 }
28 
30 {
32 
33  if (m_PropertyList.IsNull() || m_PropertyList->IsEmpty())
34  {
35  MITK_ERROR << "Not serializing nullptr or empty PropertyList";
36  return "";
37  }
38 
39  // tmpname
40  static unsigned long count = 1;
41  unsigned long n = count++;
42  std::ostringstream name;
43  for (int i = 0; i < 6; ++i)
44  {
45  name << char('a' + (n % 26));
46  n /= 26;
47  }
48  std::string filename;
49  filename.append(name.str());
50 
51  std::string fullname(m_WorkingDirectory);
52  fullname += "/";
53  fullname += filename;
54  fullname = itksys::SystemTools::ConvertToOutputPath(fullname.c_str());
55 
56  // Trim quotes
57  std::string::size_type length = fullname.length();
58 
59  if (length >= 2 && fullname[0] == '"' && fullname[length - 1] == '"')
60  fullname = fullname.substr(1, length - 2);
61 
62  TiXmlDocument document;
63  auto decl = new TiXmlDeclaration("1.0", "", ""); // TODO what to write here? encoding? etc....
64  document.LinkEndChild(decl);
65 
66  auto version = new TiXmlElement("Version");
67  version->SetAttribute("Writer", __FILE__);
68  version->SetAttribute("Revision", "$Revision: 17055 $");
69  version->SetAttribute("FileVersion", 1);
70  document.LinkEndChild(version);
71 
72  // add XML contents
73  const PropertyList::PropertyMap *propmap = m_PropertyList->GetMap();
74  for (auto iter = propmap->begin(); iter != propmap->end(); ++iter)
75  {
76  std::string key = iter->first;
77  const BaseProperty *property = iter->second;
78  TiXmlElement *element = SerializeOneProperty(key, property);
79  if (element)
80  {
81  document.LinkEndChild(element);
82  // TODO test serializer for error
83  }
84  else
85  {
86  m_FailedProperties->ReplaceProperty(key, const_cast<BaseProperty *>(property));
87  }
88  }
89 
90  // save XML file
91  if (!document.SaveFile(fullname))
92  {
93  MITK_ERROR << "Could not write PropertyList to " << fullname << "\nTinyXML reports '" << document.ErrorDesc()
94  << "'";
95  return "";
96  }
97 
98  return filename;
99 }
100 
101 TiXmlElement *mitk::PropertyListSerializer::SerializeOneProperty(const std::string &key, const BaseProperty *property)
102 {
103  auto keyelement = new TiXmlElement("property");
104  keyelement->SetAttribute("key", key);
105  keyelement->SetAttribute("type", property->GetNameOfClass());
106 
107  // construct name of serializer class
108  std::string serializername(property->GetNameOfClass());
109  serializername += "Serializer";
110 
111  std::list<itk::LightObject::Pointer> allSerializers =
112  itk::ObjectFactoryBase::CreateAllInstance(serializername.c_str());
113  if (allSerializers.size() < 1)
114  {
115  MITK_ERROR << "No serializer found for " << property->GetNameOfClass() << ". Skipping object";
116  }
117  if (allSerializers.size() > 1)
118  {
119  MITK_WARN << "Multiple serializers found for " << property->GetNameOfClass() << "Using arbitrarily the first one.";
120  }
121 
122  for (auto iter = allSerializers.begin(); iter != allSerializers.end(); ++iter)
123  {
124  if (auto *serializer = dynamic_cast<BasePropertySerializer *>(iter->GetPointer()))
125  {
126  serializer->SetProperty(property);
127  try
128  {
129  TiXmlElement *valueelement = serializer->Serialize();
130  if (valueelement)
131  {
132  keyelement->LinkEndChild(valueelement);
133  }
134  }
135  catch (std::exception &e)
136  {
137  MITK_ERROR << "Serializer " << serializer->GetNameOfClass() << " failed: " << e.what();
138  // \TODO: log only if all potential serializers fail?
139  }
140  break;
141  }
142  else
143  {
144  MITK_ERROR << "Found a serializer called '" << (*iter)->GetNameOfClass()
145  << "' that does not implement the BasePropertySerializer interface.";
146  continue;
147  }
148  }
149 
150  if (keyelement->NoChildren())
151  {
152  m_FailedProperties->ReplaceProperty(key, const_cast<BaseProperty *>(property));
153  return nullptr;
154  }
155  else
156  {
157  return keyelement;
158  }
159 }
160 
162 {
163  if (m_FailedProperties.IsNotNull() && !m_FailedProperties->IsEmpty())
164  {
165  return m_FailedProperties;
166  }
167  else
168  {
169  return nullptr;
170  }
171 }
static Pointer New()
virtual std::string Serialize()
Serializes given PropertyList object.
#define MITK_ERROR
Definition: mitkLogMacros.h:20
Key-value list holding instances of BaseProperty.
Abstract base class for properties.
#define MITK_WARN
Definition: mitkLogMacros.h:19
std::map< std::string, BaseProperty::Pointer > PropertyMap
TiXmlElement * SerializeOneProperty(const std::string &key, const BaseProperty *property)