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