OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
ossimXmlDocument.cpp
Go to the documentation of this file.
1 //*******************************************************************
2 //
3 // License: LGPL
4 //
5 // See LICENSE.txt file in the top level directory for more details.
6 //
7 // Author: Oscar Kramer (ossim port by D. Burken)
8 //
9 // Description:
10 //
11 // Contains definition of class ossimXmlDocument. This class provides read-only
12 // parsing and accessing of an XML document file.
13 //*****************************************************************************
14 // $Id: ossimXmlDocument.cpp 23258 2015-04-15 15:54:10Z dburken $
15 
16 
20 #include <ossim/base/ossimRegExp.h>
23 #include <stack>
24 #include <iostream>
25 #include <fstream>
26 
27 
28 // Static trace for debugging
29 #include <ossim/base/ossimTrace.h>
30 static ossimTrace traceDebug("ossimXmlDocument:debug");
31 
32 static std::istream& xmlskipws(std::istream& in)
33 {
34  int c = in.peek();
35  while((!in.fail())&&
36  (( (c == ' ') || (c == '\t') || (c == '\n')|| (c == '\r') || (c<0x20) || (c>=0x7f) )))//|| (c<0x20) || (c >=0x2f) )))
37  {
38  in.ignore(1);
39  c = in.peek();
40  }
41 
42  return in;
43 }
44 
45 static const int BUFFER_MAX_LEN = 1000;
46 static const ossimString XPATH_DELIM ("/");
47 
48 RTTI_DEF1(ossimXmlDocument, "ossimXmlDocument", ossimObject)
50  :
51  theRootNode (0),
52  theXmlHeader("<?xml version='1.0'?>"),
53  theStrictCheckFlag(false)
54 {
55  if(xmlFileName != "")
56  {
57  openFile(xmlFileName);
58  }
59 }
60 
62 :ossimObject(src),
63 theRootNode(src.theRootNode.valid()?(ossimXmlNode*)src.theRootNode->dup():(ossimXmlNode*)0),
64 theXmlHeader(src.theXmlHeader),
65 theFilename(src.theFilename),
66 theStrictCheckFlag(src.theStrictCheckFlag)
67 {
68 
69 }
70 
72 {
73 }
74 
76 {
77  std::ofstream out(file.c_str());
78 
79  if(out)
80  {
81  out << *this << std::endl;
82  }
83  else
84  {
85  return false;
86  }
87 
88  return true;
89 }
90 
92 {
93 
94  theFilename = filename;
95 
96  if(theFilename == "")
97  {
98  return false;
99  }
100 
101  //
102  // Open XML File:
103  // Note: Opening text document binary to overcome an apparent windows bug.
104  //
105  ifstream xml_stream (filename.c_str(), ios::binary);
106  if (!xml_stream)
107  {
108  if (traceDebug())
109  {
111  << "DEBUG: ossimXmlDocument::ossimXmlDocument\n"
112  << "encountered opening file <" << filename << "> for "
113  << "reading. Aborting..." << endl;
114  }
115  return false;
116  }
117 
118  return read(xml_stream);
119 }
120 
122 {
123 // char buffer[BUFFER_MAX_LEN];
124 // streampos file_pos;
125 // bool readingHeader = true;
126  bool startTagCharacterFound = false;
127  char c = in.peek();
128 
129  // Initially we will do our own skipping to make sure we ar not binary.
130  while(!in.bad() && (c != '<') && (c >= 0x20) && (c <= 0x7e))
131  {
132  in.ignore(1);
133  c = in.peek();
134  }
135 
136  if (in.bad() || (c!='<'))
137  {
138  setErrorStatus();
139  return false;
140  }
141  startTagCharacterFound = true;
142 
143  if(readHeader(in))
144  {
145  if(theXmlHeader=="")
146  {
147  if(startTagCharacterFound)
148  {
149  theXmlHeader = "<?xml version='1.0'?>";
150  }
151  }
152  }
153  if((!theXmlHeader.contains("xml version")) && theStrictCheckFlag)
154  {
155  if (traceDebug())
156  {
158  << "FATAL: ossimXmlDocument::ossimXmlDocument"
159  << "encountered parsing XML file <" << theFilename
160  << ">. The file does not appear to be XML v1.0. \n"
161  << "Header = \n" << theXmlHeader <<"\n"
162  << endl;
163  }
164  setErrorStatus();
165  return false;
166  }
167  theRootNode = new ossimXmlNode(in, 0);
170 }
171 
173  vector<ossimRefPtr<ossimXmlNode> >& result) const
174 {
175  //
176  // First verify the root node exists:
177  //
178  if (!theRootNode.valid())
179  {
180  if (traceDebug())
181  {
183  << "WARNING: ossimXmlDocument::findNodes,\n"
184  << "No root node has been instantiated. Returning null "
185  << "node list..." << endl;
186  }
187  return;
188  }
189 
190  //
191  // Make a copy to manipulate:
192  //
193  ossimString xpath (arg_xpath);
194  if (xpath.empty())
195  return;
196 
197  //
198  // Check if absolute path:
199  //
200  if (xpath[static_cast<std::string::size_type>(0)] !=
201  XPATH_DELIM[static_cast<std::string::size_type>(0)])
202  {
203  if (traceDebug())
204  {
206  << "WARNING: ossimXmlDocument::findNodes\n"
207  << "Only absolute XPaths are supported. Returning null "
208  << "node list..." << endl;
209  }
210  return;
211  }
212 
213  //
214  // Check that root tag matches path root:
215  //
216  ossimString rel_xpath (xpath.after(XPATH_DELIM));
217  ossimString root_tag (rel_xpath);
218  if (root_tag.contains(XPATH_DELIM))
219  root_tag = rel_xpath.before(XPATH_DELIM);
220 
221  if (root_tag != theRootNode->getTag())
222  {
223  if (traceDebug())
224  {
226  << "WARNING: ossimXmlDocument::findNodes\n"
227  << "XPath's root node <"<<root_tag<<"> does not match the "
228  << "stored root node's tag <" << theRootNode->getTag() << ">. "
229  << "Returning null node list..." << endl;
230  }
231  return;
232  }
233 
234  //
235  // If the root node was the requested node, return it alone:
236  //
237  rel_xpath = rel_xpath.after(XPATH_DELIM);
238  if (rel_xpath.empty())
239  {
240  result.push_back(theRootNode);
241  return;
242  }
243 
244  //
245  // Pass the node request on to the root node with the relative path:
246  //
247  theRootNode->findChildNodes(rel_xpath, result);
248 }
249 
251 {
252  os << xml_doc.theXmlHeader << endl;
253  if (xml_doc.theRootNode.valid())
254  {
255  os << (xml_doc.theRootNode.get()) << endl;
256  }
257 // else
258 // os << "-- no root node assigned -- " << endl;
259 
260  return os;
261 }
262 
264 {
265  theRootNode = node;
266 }
267 
269 {
270  return theRootNode;
271 }
272 
274 {
275  return theRootNode;
276 }
277 
279 {
281 
282  theRootNode = 0;
283 
284  return root;
285 }
286 
287 
289 {
290 
291  ossimKeywordlist kwl = kwlToConvert;
292  theRootNode = 0;
294 
295 
296  ossimString prefix = "";
298  ossimKeywordlist::KeywordMap::iterator mapIter = map.begin();
299 
300  while(mapIter != map.end())
301  {
302  ossimString key = mapIter->first;
303  key = key.substitute(".", "/", true);
304  theRootNode->addNode(key, mapIter->second);
305  ++mapIter;
306  }
307 
308  // now collapse all keywordlist styles to the XML style
309  //
310  std::stack<ossimRefPtr<ossimXmlNode> > tempStack;
311  tempStack.push(theRootNode);
312  while(!tempStack.empty())
313  {
314 
315  ossimRefPtr<ossimXmlNode> node = tempStack.top();
316  tempStack.pop();
317  vector<ossimRefPtr<ossimXmlNode> >& childNodes = node->getChildNodes();
318  ossim_uint32 idx = 0;
319  for(idx = 0; idx < childNodes.size(); ++idx)
320  {
321  tempStack.push(childNodes[idx]);
322  }
323  if(node->getChildNodes().size() > 0)
324  {
325  if(node->getTag()!="")
326  {
327  node->addAttribute("name", node->getTag());
328  }
329  node->setTag("object");
330  }
331 
332  if(node->getTag() == "type")
333  {
334  if(node->getParentNode())
335  {
336  node->getParentNode()->removeChild("type");
337  node->getParentNode()->addAttribute("type", node->getText());
338  }
339  }
340  else if(node->getChildNodes().size() < 1)
341  {
342  if(node->getTag()!="")
343  {
344  node->addAttribute("name", node->getTag());
345  }
346  if(!node->getText().contains("\n"))
347  {
348  if(node->getText()!="")
349  {
350  node->addAttribute("value", node->getText());
351  node->setText("");
352  }
353  }
354  node->setTag("property");
355  }
356  }
357 }
358 
360  const ossimString& prefix)const
361 {
362  if(theRootNode.valid())
363  {
364  theRootNode->toKwl(kwl, prefix);
365  }
366 // const std::vector<ossimRefPtr<ossimXmlNode> >& children = theRootNode->getChildNodes();
367 
368 // ossim_uint32 idx = 0;
369 
370 // for(idx = 0; idx < children.size(); ++idx)
371 // {
372 // children[idx]->toKwl(kwl, prefix);
373 // }
374 }
375 
377 {
378  //---
379  // Clear the existing header so we don't get double:
380  // <?xml version='1.0'?><?xml version='1.0'?>
381  //---
383 
384  char c;
385  in>>xmlskipws;
386 
387  while(in.peek() == '<')
388  {
389  std::stack<char> theLessThanStack;
390  theLessThanStack.push('<');
391  in.ignore(1);
392  c = in.peek();
393  // we will for now skip things like !DOCTYPE and any other things in the header of the document that start with <? or <!
394  if((c == '?')||
395  (c == '!'))
396  {
397  theXmlHeader += "<";
398  theXmlHeader += (char)in.get();
399 
400  while(!theLessThanStack.empty()&&
401  (!in.bad()))
402  {
403  if(in.peek() == '<')
404  {
405  theLessThanStack.push('<');
406  }
407  else if(in.peek() == '>')
408  {
409  theLessThanStack.pop();
410  }
411  theXmlHeader += (char)in.get();
412  }
413  if(!in.bad())
414  {
415  if(in.peek()=='\n'||
416  in.peek()=='\r')
417  {
418  theXmlHeader += (char)in.get();
419  }
420  }
421 // if(!in.bad())
422 // {
423 // theXmlHeader += (char)in.get();
424 // }
425  in>>xmlskipws;
426  }
427  }
428 
429  return (!in.bad());
430 }
void clear()
Erases the entire container.
Definition: ossimString.h:432
void setTag(const ossimString &tag)
ossimString substitute(const ossimString &searchKey, const ossimString &replacementValue, bool replaceAll=false) const
Substitutes searchKey string with replacementValue and returns a string.
ostream & operator<<(ostream &os, const ossimXmlDocument &xml_doc)
void setText(const ossimString &text)
void findChildNodes(const ossimString &rel_xpath, ossimXmlNode::ChildListType &nodelist) const
Represents serializable keyword/value map.
bool write(const ossimFilename &file)
static const ossimErrorCode OSSIM_OK
std::basic_ifstream< char > ifstream
Class for char input file streams.
Definition: ossimIosFwd.h:44
bool valid() const
Definition: ossimRefPtr.h:75
const ossimXmlNode::ChildListType & getChildNodes() const
ossimString const & getTag() const
Definition: ossimXmlNode.h:53
bool contains(char aChar) const
Definition: ossimString.h:58
ossimRefPtr< ossimXmlNode > addNode(const ossimString &relPath, const ossimString &text="")
void toKwl(ossimKeywordlist &kwl, const ossimString &prefix="") const
ossimRefPtr< ossimXmlNode > removeChild(ossimRefPtr< ossimXmlNode > node)
void push_back(char c)
Equivalent to insert(end(), c).
Definition: ossimString.h:905
const ossimString & getText() const
Definition: ossimXmlNode.h:92
bool openFile(const ossimFilename &filename)
void fromKwl(const ossimKeywordlist &kwl)
std::map< std::string, std::string > KeywordMap
const ossimXmlNode * getParentNode() const
virtual ~ossimXmlDocument()
ossimRefPtr< ossimXmlNode > removeRoot()
ossimFilename theFilename
unsigned int ossim_uint32
ossimString theXmlHeader
ossimRefPtr< ossimXmlNode > theRootNode
std::basic_istream< char > istream
Base class for char input streams.
Definition: ossimIosFwd.h:20
const ossimKeywordlist::KeywordMap & getMap() const
bool readHeader(std::istream &in)
virtual ossimErrorCode getErrorStatus() const
ossimXmlDocument(const ossimFilename &xmlFileName="")
void toKwl(ossimKeywordlist &kwl, const ossimString &prefix="") const
const char * c_str() const
Returns a pointer to a null-terminated array of characters representing the string&#39;s contents...
Definition: ossimString.h:396
bool empty() const
Definition: ossimString.h:411
bool read(std::istream &in)
void addAttribute(ossimRefPtr< ossimXmlAttribute > attribute)
std::basic_ofstream< char > ofstream
Class for char output file streams.
Definition: ossimIosFwd.h:47
void findNodes(const ossimString &xpath, std::vector< ossimRefPtr< ossimXmlNode > > &nodelist) const
Appends any matching nodes to the list supplied (should be empty):
#define RTTI_DEF1(cls, name, b1)
Definition: ossimRtti.h:485
ossimRefPtr< ossimXmlNode > getRoot()
ossimString after(const ossimString &str, std::string::size_type pos=0) const
METHOD: after(str, pos) Returns string immediately after the token str.
void initRoot(ossimRefPtr< ossimXmlNode > node)
OSSIMDLLEXPORT std::ostream & ossimNotify(ossimNotifyLevel level=ossimNotifyLevel_WARN)
std::basic_ostream< char > ostream
Base class for char output streams.
Definition: ossimIosFwd.h:23