1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkXMLTreeReader.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15 /*-------------------------------------------------------------------------
16 Copyright 2008 Sandia Corporation.
17 Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
18 the U.S. Government retains certain rights in this software.
19 -------------------------------------------------------------------------*/
20
21 #include "vtkXMLTreeReader.h"
22
23 #include "vtkBitArray.h"
24 #include "vtkIdTypeArray.h"
25 #include "vtkInformation.h"
26 #include "vtkMutableDirectedGraph.h"
27 #include "vtkObjectFactory.h"
28 #include "vtkPointData.h"
29 #include "vtkSmartPointer.h"
30 #include "vtkStringArray.h"
31 #include "vtkTree.h"
32
33 #include "vtk_libxml2.h"
34 #include VTKLIBXML2_HEADER(parser.h)
35 #include VTKLIBXML2_HEADER(tree.h)
36
37 vtkStandardNewMacro(vtkXMLTreeReader);
38
39 const char* vtkXMLTreeReader::TagNameField = ".tagname";
40 const char* vtkXMLTreeReader::CharDataField = ".chardata";
41
vtkXMLTreeReader()42 vtkXMLTreeReader::vtkXMLTreeReader()
43 {
44 this->FileName = nullptr;
45 this->XMLString = nullptr;
46 this->SetNumberOfInputPorts(0);
47 this->SetNumberOfOutputPorts(1);
48 this->ReadCharData = false;
49 this->ReadTagName = true;
50 this->MaskArrays = false;
51 this->EdgePedigreeIdArrayName = nullptr;
52 this->SetEdgePedigreeIdArrayName("edge id");
53 this->VertexPedigreeIdArrayName = nullptr;
54 this->SetVertexPedigreeIdArrayName("vertex id");
55 this->GenerateEdgePedigreeIds = true;
56 this->GenerateVertexPedigreeIds = true;
57 }
58
~vtkXMLTreeReader()59 vtkXMLTreeReader::~vtkXMLTreeReader()
60 {
61 this->SetFileName(nullptr);
62 this->SetXMLString(nullptr);
63 this->SetEdgePedigreeIdArrayName(nullptr);
64 this->SetVertexPedigreeIdArrayName(nullptr);
65 }
66
PrintSelf(ostream & os,vtkIndent indent)67 void vtkXMLTreeReader::PrintSelf(ostream& os, vtkIndent indent)
68 {
69 this->Superclass::PrintSelf(os, indent);
70 os << indent << "FileName: " << (this->FileName ? this->FileName : "(none)") << endl;
71 os << indent << "ReadCharData: " << (this->ReadCharData ? "on" : "off") << endl;
72 os << indent << "ReadTagName: " << (this->ReadTagName ? "on" : "off") << endl;
73 os << indent << "MaskArrays: " << (this->MaskArrays ? "on" : "off") << endl;
74 os << indent << "XMLString: " << (this->XMLString ? this->XMLString : "(none)") << endl;
75 os << indent << "EdgePedigreeIdArrayName: "
76 << (this->EdgePedigreeIdArrayName ? this->EdgePedigreeIdArrayName : "(null)") << endl;
77 os << indent << "VertexPedigreeIdArrayName: "
78 << (this->VertexPedigreeIdArrayName ? this->VertexPedigreeIdArrayName : "(null)") << endl;
79 os << indent << "GenerateEdgePedigreeIds: " << (this->GenerateEdgePedigreeIds ? "on" : "off")
80 << endl;
81 os << indent << "GenerateVertexPedigreeIds: " << (this->GenerateVertexPedigreeIds ? "on" : "off")
82 << endl;
83 }
84
vtkXMLTreeReaderProcessElement(vtkMutableDirectedGraph * tree,vtkIdType parent,xmlNode * node,int readCharData,int maskArrays)85 static void vtkXMLTreeReaderProcessElement(
86 vtkMutableDirectedGraph* tree, vtkIdType parent, xmlNode* node, int readCharData, int maskArrays)
87 {
88 vtkDataSetAttributes* data = tree->GetVertexData();
89 vtkStringArray* nameArr =
90 vtkArrayDownCast<vtkStringArray>(data->GetAbstractArray(vtkXMLTreeReader::TagNameField));
91 vtkStdString content;
92 for (xmlNode* curNode = node; curNode; curNode = curNode->next)
93 {
94 // cerr << "type=" << curNode->type << ",name=" << curNode->name << endl;
95 if (curNode->content)
96 {
97 const char* curContent = reinterpret_cast<const char*>(curNode->content);
98 content += curContent;
99 // cerr << "content=" << curNode->content << endl;
100 }
101
102 if (curNode->type != XML_ELEMENT_NODE)
103 {
104 continue;
105 }
106
107 vtkIdType vertex = tree->AddVertex();
108 if (parent != -1)
109 {
110 tree->AddEdge(parent, vertex);
111 }
112
113 // Append the node tag and character data to the vtkPointData
114 if (nameArr) // If the reader has ReadTagName = ON then populate this array
115 {
116 nameArr->InsertValue(vertex, reinterpret_cast<const char*>(curNode->name));
117 }
118
119 // Append the element attributes to the vtkPointData
120 for (xmlAttr* curAttr = curNode->properties; curAttr; curAttr = curAttr->next)
121 {
122 const char* name = reinterpret_cast<const char*>(curAttr->name);
123 int len = static_cast<int>(strlen(name));
124 char* validName = new char[len + 8];
125 strcpy(validName, ".valid.");
126 strcat(validName, name);
127 vtkStringArray* stringArr = vtkArrayDownCast<vtkStringArray>(data->GetAbstractArray(name));
128 vtkBitArray* bitArr = nullptr;
129 if (maskArrays)
130 {
131 bitArr = vtkArrayDownCast<vtkBitArray>(data->GetAbstractArray(validName));
132 }
133 if (!stringArr)
134 {
135 stringArr = vtkStringArray::New();
136 stringArr->SetName(name);
137 data->AddArray(stringArr);
138 stringArr->Delete();
139 if (maskArrays)
140 {
141 bitArr = vtkBitArray::New();
142 bitArr->SetName(validName);
143 data->AddArray(bitArr);
144 bitArr->Delete();
145 }
146 }
147 const char* value = reinterpret_cast<const char*>(curAttr->children->content);
148 stringArr->InsertValue(vertex, value);
149 if (maskArrays)
150 {
151 for (vtkIdType i = bitArr->GetNumberOfTuples(); i < vertex; i++)
152 {
153 bitArr->InsertNextValue(false);
154 }
155 bitArr->InsertNextValue(true);
156 }
157 // cerr << "attname=" << name << ",value=" << value << endl;
158 delete[] validName;
159 }
160
161 // Process this node's children
162 vtkXMLTreeReaderProcessElement(tree, vertex, curNode->children, readCharData, maskArrays);
163 }
164
165 if (readCharData && parent >= 0)
166 {
167 vtkStringArray* charArr =
168 vtkArrayDownCast<vtkStringArray>(data->GetAbstractArray(vtkXMLTreeReader::CharDataField));
169 charArr->InsertValue(parent, content);
170 }
171 }
172
RequestData(vtkInformation *,vtkInformationVector **,vtkInformationVector * outputVector)173 int vtkXMLTreeReader::RequestData(
174 vtkInformation*, vtkInformationVector**, vtkInformationVector* outputVector)
175 {
176 if (!this->FileName && !this->XMLString)
177 {
178 vtkErrorMacro("A FileName or XMLString must be specified");
179 return 0;
180 }
181
182 xmlDoc* doc = nullptr;
183 if (this->FileName)
184 {
185 // Parse the file and get the DOM
186 doc = xmlReadFile(this->FileName, nullptr, 0);
187 }
188 else if (this->XMLString)
189 {
190 // Parse from memory and get the DOM
191 doc = xmlReadMemory(
192 this->XMLString, static_cast<int>(strlen(this->XMLString)), "noname.xml", nullptr, 0);
193 }
194
195 // Store the XML hierarchy into a vtkMutableDirectedGraph,
196 // later to be placed in a vtkTree.
197 vtkSmartPointer<vtkMutableDirectedGraph> builder =
198 vtkSmartPointer<vtkMutableDirectedGraph>::New();
199
200 vtkDataSetAttributes* data = builder->GetVertexData();
201
202 if (this->ReadTagName)
203 {
204 vtkStringArray* nameArr = vtkStringArray::New();
205 nameArr->SetName(vtkXMLTreeReader::TagNameField);
206 data->AddArray(nameArr);
207 nameArr->Delete();
208 }
209
210 if (this->ReadCharData)
211 {
212 vtkStringArray* charArr = vtkStringArray::New();
213 charArr->SetName(vtkXMLTreeReader::CharDataField);
214 data->AddArray(charArr);
215 charArr->Delete();
216 }
217
218 // Get the root element node
219 xmlNode* rootElement = xmlDocGetRootElement(doc);
220 vtkXMLTreeReaderProcessElement(builder, -1, rootElement, this->ReadCharData, this->MaskArrays);
221
222 xmlFreeDoc(doc);
223
224 // Make all the arrays the same size
225 for (int i = 0; i < data->GetNumberOfArrays(); i++)
226 {
227 vtkStringArray* stringArr = vtkArrayDownCast<vtkStringArray>(data->GetAbstractArray(i));
228 if (stringArr && (stringArr->GetNumberOfTuples() < builder->GetNumberOfVertices()))
229 {
230 stringArr->InsertValue(builder->GetNumberOfVertices() - 1, vtkStdString(""));
231 }
232 }
233
234 // Move the XML hierarchy into a vtkTree
235 vtkTree* output = vtkTree::GetData(outputVector);
236 if (!output->CheckedShallowCopy(builder))
237 {
238 vtkErrorMacro(<< "Structure is not a valid tree!");
239 return 0;
240 }
241
242 // Look for or generate vertex pedigree id array.
243 if (this->GenerateVertexPedigreeIds)
244 {
245 // Create vertex pedigree ids
246 vtkSmartPointer<vtkIdTypeArray> ids = vtkSmartPointer<vtkIdTypeArray>::New();
247 ids->SetName(this->VertexPedigreeIdArrayName);
248 vtkIdType numVerts = output->GetNumberOfVertices();
249 ids->SetNumberOfTuples(numVerts);
250 for (vtkIdType i = 0; i < numVerts; ++i)
251 {
252 ids->SetValue(i, i);
253 }
254 output->GetVertexData()->SetPedigreeIds(ids);
255 }
256 else
257 {
258 vtkAbstractArray* pedIds =
259 output->GetVertexData()->GetAbstractArray(this->VertexPedigreeIdArrayName);
260 if (pedIds)
261 {
262 output->GetVertexData()->SetPedigreeIds(pedIds);
263 }
264 else
265 {
266 vtkErrorMacro(<< "Vertex pedigree ID array not found.");
267 return 0;
268 }
269 }
270
271 // Look for or generate edge pedigree id array.
272 if (this->GenerateEdgePedigreeIds)
273 {
274 // Create vertex pedigree ids
275 vtkSmartPointer<vtkIdTypeArray> ids = vtkSmartPointer<vtkIdTypeArray>::New();
276 ids->SetName(this->EdgePedigreeIdArrayName);
277 vtkIdType numEdges = output->GetNumberOfEdges();
278 ids->SetNumberOfTuples(numEdges);
279 for (vtkIdType i = 0; i < numEdges; ++i)
280 {
281 ids->SetValue(i, i);
282 }
283 output->GetEdgeData()->SetPedigreeIds(ids);
284 }
285 else
286 {
287 vtkAbstractArray* pedIds =
288 output->GetEdgeData()->GetAbstractArray(this->EdgePedigreeIdArrayName);
289 if (pedIds)
290 {
291 output->GetEdgeData()->SetPedigreeIds(pedIds);
292 }
293 else
294 {
295 vtkErrorMacro(<< "Edge pedigree ID array not found.");
296 return 0;
297 }
298 }
299
300 return 1;
301 }
302