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 "vtkInformation.h"
25 #include "vtkIdTypeArray.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 = 0;
45   this->XMLString = 0;
46   this->SetNumberOfInputPorts(0);
47   this->SetNumberOfOutputPorts(1);
48   this->ReadCharData = 0;
49   this->ReadTagName = 1;
50   this->MaskArrays = 0;
51   this->EdgePedigreeIdArrayName = 0;
52   this->SetEdgePedigreeIdArrayName("edge id");
53   this->VertexPedigreeIdArrayName = 0;
54   this->SetVertexPedigreeIdArrayName("vertex id");
55   this->GenerateEdgePedigreeIds = true;
56   this->GenerateVertexPedigreeIds = true;
57 }
58 
~vtkXMLTreeReader()59 vtkXMLTreeReader::~vtkXMLTreeReader()
60 {
61   this->SetFileName(0);
62   this->SetXMLString(0);
63   this->SetEdgePedigreeIdArrayName(0);
64   this->SetVertexPedigreeIdArrayName(0);
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: "
71      << (this->FileName ? this->FileName : "(none)") << endl;
72   os << indent << "ReadCharData: "
73      << (this->ReadCharData ? "on" : "off") << endl;
74   os << indent << "ReadTagName: "
75      << (this->ReadTagName ? "on" : "off") << endl;
76   os << indent << "MaskArrays: "
77      << (this->MaskArrays ? "on" : "off") << endl;
78   os << indent << "XMLString: "
79      << (this->XMLString ? this->XMLString : "(none)") << endl;
80   os << indent << "EdgePedigreeIdArrayName: "
81      << (this->EdgePedigreeIdArrayName ? this->EdgePedigreeIdArrayName : "(null)") << endl;
82   os << indent << "VertexPedigreeIdArrayName: "
83      << (this->VertexPedigreeIdArrayName ? this->VertexPedigreeIdArrayName : "(null)") << endl;
84   os << indent << "GenerateEdgePedigreeIds: "
85      << (this->GenerateEdgePedigreeIds ? "on" : "off") << endl;
86   os << indent << "GenerateVertexPedigreeIds: "
87      << (this->GenerateVertexPedigreeIds ? "on" : "off") << endl;
88 }
89 
vtkXMLTreeReaderProcessElement(vtkMutableDirectedGraph * tree,vtkIdType parent,xmlNode * node,int readCharData,int maskArrays)90 static void vtkXMLTreeReaderProcessElement(vtkMutableDirectedGraph *tree,
91    vtkIdType parent, xmlNode *node, int readCharData, int maskArrays)
92 {
93   vtkDataSetAttributes *data = tree->GetVertexData();
94   vtkStringArray *nameArr = vtkStringArray::SafeDownCast(data->GetAbstractArray(vtkXMLTreeReader::TagNameField));
95   vtkStdString content;
96   for (xmlNode *curNode = node; curNode; curNode = curNode->next)
97     {
98     //cerr << "type=" << curNode->type << ",name=" << curNode->name << endl;
99     if (curNode->content)
100       {
101       const char *curContent = reinterpret_cast<const char*>(curNode->content);
102       content += curContent;
103       //cerr << "content=" << curNode->content << endl;
104       }
105 
106     if (curNode->type != XML_ELEMENT_NODE)
107       {
108       continue;
109       }
110 
111     vtkIdType vertex = -1;
112     vertex = tree->AddVertex();
113     if (parent != -1)
114       {
115       tree->AddEdge(parent, vertex);
116       }
117 
118     // Append the node tag and character data to the vtkPointData
119     if (nameArr) // If the reader has ReadTagName = ON then populate this array
120       {
121       nameArr->InsertValue(vertex, reinterpret_cast<const char*>(curNode->name));
122       }
123 
124     // Append the element attributes to the vtkPointData
125     for (xmlAttr *curAttr = curNode->properties; curAttr; curAttr = curAttr->next)
126       {
127       const char *name = reinterpret_cast<const char*>(curAttr->name);
128       int len = static_cast<int>(strlen(name));
129       char *validName = new char[len+8];
130       strcpy(validName, ".valid.");
131       strcat(validName, name);
132       vtkStringArray *stringArr = vtkStringArray::SafeDownCast(data->GetAbstractArray(name));
133       vtkBitArray *bitArr = 0;
134       if (maskArrays)
135         {
136         bitArr = vtkBitArray::SafeDownCast(data->GetAbstractArray(validName));
137         }
138       if (!stringArr)
139         {
140         stringArr = vtkStringArray::New();
141         stringArr->SetName(name);
142         data->AddArray(stringArr);
143         stringArr->Delete();
144         if (maskArrays)
145           {
146           bitArr = vtkBitArray::New();
147           bitArr->SetName(validName);
148           data->AddArray(bitArr);
149           bitArr->Delete();
150           }
151         }
152       const char *value = reinterpret_cast<const char*>(curAttr->children->content);
153       stringArr->InsertValue(vertex, value);
154       if (maskArrays)
155         {
156         for (vtkIdType i = bitArr->GetNumberOfTuples(); i < vertex; i++)
157           {
158           bitArr->InsertNextValue(false);
159           }
160         bitArr->InsertNextValue(true);
161         }
162       //cerr << "attname=" << name << ",value=" << value << endl;
163       delete [] validName;
164       }
165 
166     // Process this node's children
167     vtkXMLTreeReaderProcessElement(tree, vertex, curNode->children, readCharData, maskArrays);
168     }
169 
170   if (readCharData && parent >= 0)
171     {
172     vtkStringArray *charArr = vtkStringArray::SafeDownCast(data->GetAbstractArray(vtkXMLTreeReader::CharDataField));
173     charArr->InsertValue(parent, content);
174     }
175 }
176 
RequestData(vtkInformation *,vtkInformationVector **,vtkInformationVector * outputVector)177 int vtkXMLTreeReader::RequestData(
178   vtkInformation*,
179   vtkInformationVector**,
180   vtkInformationVector *outputVector)
181 {
182   if (!this->FileName && !this->XMLString)
183     {
184     vtkErrorMacro("A FileName or XMLString must be specified");
185     return 0;
186     }
187 
188   xmlDoc *doc = NULL;
189   if (this->FileName)
190     {
191     // Parse the file and get the DOM
192     doc = xmlReadFile(this->FileName, NULL, 0);
193     }
194   else if (this->XMLString)
195     {
196     // Parse from memory and get the DOM
197     doc = xmlReadMemory(this->XMLString, static_cast<int>(strlen(this->XMLString)), "noname.xml", NULL, 0);
198     }
199 
200   // Store the XML hierarchy into a vtkMutableDirectedGraph,
201   // later to be placed in a vtkTree.
202   vtkSmartPointer<vtkMutableDirectedGraph> builder =
203     vtkSmartPointer<vtkMutableDirectedGraph>::New();
204 
205   vtkDataSetAttributes *data = builder->GetVertexData();
206 
207   if (this->ReadTagName)
208     {
209     vtkStringArray *nameArr = vtkStringArray::New();
210     nameArr->SetName(vtkXMLTreeReader::TagNameField);
211     data->AddArray(nameArr);
212     nameArr->Delete();
213     }
214 
215   if (this->ReadCharData)
216     {
217     vtkStringArray *charArr = vtkStringArray::New();
218     charArr->SetName(vtkXMLTreeReader::CharDataField);
219     data->AddArray(charArr);
220     charArr->Delete();
221     }
222 
223   // Get the root element node
224   xmlNode *rootElement = xmlDocGetRootElement(doc);
225   vtkXMLTreeReaderProcessElement(builder, -1, rootElement, this->ReadCharData, this->MaskArrays);
226 
227   xmlFreeDoc(doc);
228 
229   // Make all the arrays the same size
230   for (int i = 0; i < data->GetNumberOfArrays(); i++)
231     {
232     vtkStringArray *stringArr = vtkStringArray::SafeDownCast(data->GetAbstractArray(i));
233     if (stringArr && (stringArr->GetNumberOfTuples() < builder->GetNumberOfVertices()))
234       {
235       stringArr->InsertValue(builder->GetNumberOfVertices() - 1, vtkStdString(""));
236       }
237     }
238 
239   // Move the XML hierarchy into a vtkTree
240   vtkTree *output = vtkTree::GetData(outputVector);
241   if (!output->CheckedShallowCopy(builder))
242     {
243     vtkErrorMacro(<<"Structure is not a valid tree!");
244     return 0;
245     }
246 
247   // Look for or generate vertex pedigree id array.
248   if (this->GenerateVertexPedigreeIds)
249     {
250     // Create vertex pedigree ids
251     vtkSmartPointer<vtkIdTypeArray> ids = vtkSmartPointer<vtkIdTypeArray>::New();
252     ids->SetName(this->VertexPedigreeIdArrayName);
253     vtkIdType numVerts = output->GetNumberOfVertices();
254     ids->SetNumberOfTuples(numVerts);
255     for (vtkIdType i = 0; i < numVerts; ++i)
256       {
257       ids->SetValue(i, i);
258       }
259     output->GetVertexData()->SetPedigreeIds(ids);
260     }
261   else
262     {
263     vtkAbstractArray* pedIds = output->GetVertexData()->GetAbstractArray(this->VertexPedigreeIdArrayName);
264     if (pedIds)
265       {
266       output->GetVertexData()->SetPedigreeIds(pedIds);
267       }
268     else
269       {
270       vtkErrorMacro(<< "Vertex pedigree ID array not found.");
271       return 0;
272       }
273     }
274 
275   // Look for or generate edge pedigree id array.
276   if (this->GenerateEdgePedigreeIds)
277     {
278     // Create vertex pedigree ids
279     vtkSmartPointer<vtkIdTypeArray> ids = vtkSmartPointer<vtkIdTypeArray>::New();
280     ids->SetName(this->EdgePedigreeIdArrayName);
281     vtkIdType numEdges = output->GetNumberOfEdges();
282     ids->SetNumberOfTuples(numEdges);
283     for (vtkIdType i = 0; i < numEdges; ++i)
284       {
285       ids->SetValue(i, i);
286       }
287     output->GetEdgeData()->SetPedigreeIds(ids);
288     }
289   else
290     {
291     vtkAbstractArray* pedIds = output->GetEdgeData()->GetAbstractArray(this->EdgePedigreeIdArrayName);
292     if (pedIds)
293       {
294       output->GetEdgeData()->SetPedigreeIds(pedIds);
295       }
296     else
297       {
298       vtkErrorMacro(<< "Edge pedigree ID array not found.");
299       return 0;
300       }
301     }
302 
303   return 1;
304 }
305 
306