XdmfCoreReader.cpp 13.3 KB
Newer Older
Kenneth Leiter's avatar
Kenneth Leiter committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*****************************************************************************/
/*                                    XDMF                                   */
/*                       eXtensible Data Model and Format                    */
/*                                                                           */
/*  Id : XdmfCoreReader.cpp                                                  */
/*                                                                           */
/*  Author:                                                                  */
/*     Kenneth Leiter                                                        */
/*     kenneth.leiter@arl.army.mil                                           */
/*     US Army Research Laboratory                                           */
/*     Aberdeen Proving Ground, MD                                           */
/*                                                                           */
/*     Copyright @ 2011 US Army Research Laboratory                          */
/*     All Rights Reserved                                                   */
/*     See Copyright.txt for details                                         */
/*                                                                           */
/*     This software is distributed WITHOUT ANY WARRANTY; without            */
/*     even the implied warranty of MERCHANTABILITY or FITNESS               */
/*     FOR A PARTICULAR PURPOSE.  See the above copyright notice             */
/*     for more information.                                                 */
/*                                                                           */
/*****************************************************************************/
23

24 25 26 27
#define vtk_libxml2_reference reference // Reversing VTK name mangling
#include <libxml/uri.h>
#include <libxml/xpointer.h>
#include <libxml/xmlreader.h>
28
#include <cstring>
29
#include <map>
30
#include <sstream>
31 32
#include <utility>
#include "XdmfArray.hpp"
33
#include "XdmfArrayType.hpp"
34 35
#include "XdmfCoreItemFactory.hpp"
#include "XdmfCoreReader.hpp"
36
#include "XdmfError.hpp"
37
#include "XdmfItem.hpp"
38
#include "XdmfSystemUtils.hpp"
39

40 41 42 43 44 45 46
/**
 * PIMPL
 */
class XdmfCoreReader::XdmfCoreReaderImpl {

public:

47
  XdmfCoreReaderImpl(const shared_ptr<const XdmfCoreItemFactory> itemFactory,
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
                     const XdmfCoreReader * const coreReader) :
    mCoreReader(coreReader),
    mItemFactory(itemFactory)
  {
  };

  ~XdmfCoreReaderImpl()
  {
  };

  void
  closeFile()
  {
    mXPathMap.clear();
    xmlXPathFreeContext(mXPathContext);
63 64 65 66 67 68
    for(std::map<std::string, xmlDocPtr>::const_iterator iter = 
	  mDocuments.begin(); iter != mDocuments.end(); ++iter) {
      xmlFreeDoc(iter->second);
    }
    mDocuments.clear();
    
69 70 71 72 73 74 75 76 77 78 79 80
    xmlCleanupParser();
  }

  void
  openFile(const std::string & filePath)
  {
    mXMLDir = XdmfSystemUtils::getRealPath(filePath);
    size_t index = mXMLDir.find_last_of("/\\");
    if(index != std::string::npos) {
      mXMLDir = mXMLDir.substr(0, index + 1);
    }

81
    mDocument = xmlReadFile(filePath.c_str(), NULL, XML_PARSE_NOENT);
82 83

    if(mDocument == NULL) {
84 85 86
      XdmfError::message(XdmfError::FATAL,
                         "xmlReadFile could not read " + filePath +
                         " in XdmfCoreReader::XdmfCoreReaderImpl::openFile");
87 88
    }

89 90
    mDocuments.insert(std::make_pair((char*)mDocument->URL, mDocument));

91 92 93 94
    mXPathContext = xmlXPtrNewContext(mDocument, NULL, NULL);
    mXPathMap.clear();
  }

95 96 97 98 99 100
  void
  parse(const std::string & lightData) 
  {
    mDocument = xmlParseDoc((const xmlChar*)lightData.c_str());
                               
    if(mDocument == NULL) {
101 102 103
      XdmfError::message(XdmfError::FATAL,
                         "xmlReadFile could not parse passed light data string"
                         " in XdmfCoreReader::XdmfCoreReaderImpl::parse");
104
    }
105 106
    
    //mDocuments.insert(std::make_pair((char*)mDocument->URL, mDocument));
107 108 109 110
    mXPathContext = xmlXPtrNewContext(mDocument, NULL, NULL);
    mXPathMap.clear();
  }

111 112 113 114 115
  /**
   * Constructs XdmfItems for all nodes in currNode's tree.
   * XdmfItems are constructed by recursively calling this function for all
   * children of currNode.
   */
116
  std::vector<shared_ptr<XdmfItem> >
117 118
  read(xmlNodePtr currNode)
  {
119
    std::vector<shared_ptr<XdmfItem> > myItems;
120 121 122

    while(currNode != NULL) {
      if(currNode->type == XML_ELEMENT_NODE) {
123 124
        // Normal reading
        this->readSingleNode(currNode, myItems);
125 126 127 128 129 130 131 132 133 134 135 136 137
      }
      currNode = currNode->next;
    }
    return myItems;
  }

  /**
   * Reads a single xmlNode into an XdmfItem object in memory. The constructed
   * XdmfItem is added to myItems and an entry is added mapping the xmlNodePtr
   * to the new XdmfItem in the mXPathMap.
   */
  void
  readSingleNode(const xmlNodePtr currNode,
138
                 std::vector<shared_ptr<XdmfItem> > & myItems)
139
  {
140 141 142 143 144 145
    // Deal with proper resolution of XIncludes
    if(xmlStrcmp(currNode->name, (xmlChar*)"include") == 0) {
      
      xmlChar * xpointer = NULL;
      xmlChar * href = NULL;
      
146 147
      xmlAttrPtr currAttribute = currNode->properties;
      while(currAttribute != NULL) {
148 149 150 151 152 153
        if(xmlStrcmp(currAttribute->name, (xmlChar*)"xpointer") == 0) {
          xpointer = currAttribute->children->content;
        }
        if(xmlStrcmp(currAttribute->name, (xmlChar*)"href") == 0) {
          href = currAttribute->children->content;
        }
154 155
        currAttribute = currAttribute->next;
      }
156

157 158 159 160 161 162 163 164 165 166 167 168 169 170
      xmlXPathContextPtr oldContext = mXPathContext;
      if(href) {
        xmlDocPtr document;
        xmlChar * filePath = xmlBuildURI(href, mDocument->URL);
        std::map<std::string, xmlDocPtr>::const_iterator iter = 
          mDocuments.find((char*)filePath);
        if(iter == mDocuments.end()) {
          document = xmlReadFile((char*)filePath, NULL, 0);
          mDocuments.insert(std::make_pair((char*)document->URL, 
                                           document));
        }
        else {
          document = iter->second;
        }
171
	xmlFree(filePath);
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
        mXPathContext = xmlXPtrNewContext(document, NULL, NULL);           
      }
      
      if(xpointer) {
        xmlXPathObjectPtr result = xmlXPtrEval(xpointer, mXPathContext);
        if(result && !xmlXPathNodeSetIsEmpty(result->nodesetval)) {
          for(int i=0; i<result->nodesetval->nodeNr; ++i) {
            this->readSingleNode(result->nodesetval->nodeTab[i],
                                 myItems);
          }
        }
        else {
          XdmfError::message(XdmfError::FATAL,
                             "Invalid xpointer encountered.");
        }
        xmlXPathFreeObject(result);
188
      }
189 190 191 192 193 194 195 196 197
      
      if(href) {
        xmlXPathFreeContext(mXPathContext);
      }
      
      mXPathContext = oldContext;
      
    }
    else {
198

199 200 201 202 203 204
      // Check to see if the node is already in the XPath Map (seen previously)
      std::map<xmlNodePtr, shared_ptr<XdmfItem> >::const_iterator iter =
        mXPathMap.find(currNode);
      // If it is grab it from the previously stored items
      if(iter != mXPathMap.end()) {
        myItems.push_back(iter->second);
205 206
      }
      else {
207 208
        // Otherwise, generate a new XdmfItem from the node
        std::map<std::string, std::string> itemProperties;
209

210
        xmlNodePtr childNode = currNode->children;
211
        // generate content if an array or arrayReference
212
        if (mItemFactory->isArrayTag((char *)currNode->name)) {
213 214
          while(childNode != NULL) {
            if(childNode->type == XML_TEXT_NODE && childNode->content) {
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
              const char * content = (char*)childNode->content;

              // Determine if content is whitespace
              bool whitespace = true;

              const char * contentPtr = content;
              // Step through to end of pointer
              while(contentPtr != NULL) {
                // If not a whitespace character, break
                if(!isspace(*contentPtr++)) {
                  whitespace = false;
                  break;
                }
              }
              if(!whitespace) {
230
                itemProperties.insert(std::make_pair("Content", content));
231 232 233
                itemProperties.insert(std::make_pair("XMLDir", mXMLDir));
                break;
              }
234 235 236 237
            }
            childNode = childNode->next;
          }
        }
238

239 240 241 242 243 244 245
        // Pull attributes from node
        xmlAttrPtr currAttribute = currNode->properties;
        while(currAttribute != NULL) {
          itemProperties.insert(std::make_pair((char *)currAttribute->name,
                                               (char *)currAttribute->children->content));
          currAttribute = currAttribute->next;
        }
246

247 248 249
        // Build XdmfItem
        const std::vector<shared_ptr<XdmfItem> > childItems =
          this->read(currNode->children);
250
        shared_ptr<XdmfItem> newItem =
251 252 253
          mItemFactory->createItem((const char *)currNode->name,
                                   itemProperties,
                                   childItems);
254

255
        if(newItem == NULL) {
256
          XdmfError::message(XdmfError::FATAL,
257 258 259
                             "mItemFactory failed to createItem in "
                             "XdmfCoreReader::XdmfCoreReaderImpl::readSingleNode");
        }
260

261 262

        // Populate built XdmfItem
263 264 265
        newItem->populateItem(itemProperties,
                              childItems,
                              mCoreReader);
266 267 268

        myItems.push_back(newItem);
        mXPathMap.insert(std::make_pair(currNode, newItem));
269 270 271 272 273 274
      }
    }
  }

  void
  readPathObjects(const std::string & xPath,
275
                  std::vector<shared_ptr<XdmfItem> > & myItems)
276 277 278 279 280
  {
    xmlXPathObjectPtr xPathObject =
      xmlXPathEvalExpression((xmlChar*)xPath.c_str(), mXPathContext);
    if(xPathObject && xPathObject->nodesetval) {
      for(int i=0; i<xPathObject->nodesetval->nodeNr; ++i) {
281
        this->readSingleNode(xPathObject->nodesetval->nodeTab[i], myItems);
282 283 284 285 286 287
      }
    }
    xmlXPathFreeObject(xPathObject);
  }

  xmlDocPtr mDocument;
288
  std::map<std::string, xmlDocPtr> mDocuments;
289
  const XdmfCoreReader * const mCoreReader;
290
  const shared_ptr<const XdmfCoreItemFactory> mItemFactory;
291 292
  std::string mXMLDir;
  xmlXPathContextPtr mXPathContext;
293
  std::map<xmlNodePtr, shared_ptr<XdmfItem> > mXPathMap;
294 295
};

296
XdmfCoreReader::XdmfCoreReader(const shared_ptr<const XdmfCoreItemFactory> itemFactory) :
297
  mImpl(new XdmfCoreReaderImpl(itemFactory, this))
298 299 300 301 302
{
}

XdmfCoreReader::~XdmfCoreReader()
{
303
  delete mImpl;
304 305
}

306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
std::vector<shared_ptr<XdmfHeavyDataController> >
XdmfCoreReader::generateHeavyDataControllers(std::map<std::string, std::string> controllerProperties,
                                             const std::vector<unsigned int> & passedDimensions,
                                             shared_ptr<const XdmfArrayType> passedArrayType,
                                             const std::string & passedFormat) const
{
  return mImpl->mItemFactory->generateHeavyDataControllers(controllerProperties,
                                                           passedDimensions,
                                                           passedArrayType,
                                                           passedFormat);
}

shared_ptr<XdmfHeavyDataWriter>
XdmfCoreReader::generateHeavyDataWriter(std::string typeName, std::string path) const
{
  return mImpl->mItemFactory->generateHeavyDataWriter(typeName, path);
}

324 325 326
shared_ptr<XdmfItem >
XdmfCoreReader::parse(const std::string & lightData) const
{
327
  mImpl->parse(lightData);
328
  const xmlNodePtr currNode = xmlDocGetRootElement(mImpl->mDocument);
329
  std::vector<shared_ptr<XdmfItem> > toReturn;
330 331
  if(mImpl->mItemFactory->createItem((const char*)currNode->name,
                                     std::map<std::string, std::string>(),
332
                                     std::vector<shared_ptr<XdmfItem> >()) == NULL) {
333
    toReturn = mImpl->read(currNode->children);
334
  }
335 336
  else {
    toReturn = mImpl->read(currNode);
337
  }
338 339 340 341
  mImpl->closeFile();
  return(toReturn[0]);
}

342
std::vector<shared_ptr<XdmfItem> >
343
XdmfCoreReader::readItems(const std::string & filePath) const
344
{
345 346 347 348 349 350
  mImpl->openFile(filePath);
  const xmlNodePtr currNode = xmlDocGetRootElement(mImpl->mDocument);
  const std::vector<shared_ptr<XdmfItem> > toReturn =
    mImpl->read(currNode->children);
  mImpl->closeFile();
  return toReturn;
351 352
}

353
shared_ptr<XdmfItem>
354
XdmfCoreReader::read(const std::string & filePath) const
355
{
356 357 358
  const std::vector<shared_ptr<XdmfItem> > toReturn = readItems(filePath);
  if (toReturn.size() == 0) {
    return(shared_ptr<XdmfItem>());
359
  }
360
  return(toReturn[0]);
361
}
362

363
std::vector<shared_ptr<XdmfItem> >
364 365
XdmfCoreReader::read(const std::string & filePath,
                     const std::string & xPath) const
366
{
367 368 369 370
  mImpl->openFile(filePath);
  std::vector<shared_ptr<XdmfItem> > toReturn = this->readPathObjects(xPath);
  mImpl->closeFile();
  return toReturn;
371
}
372

373
std::vector<shared_ptr<XdmfItem> >
374
XdmfCoreReader::readPathObjects(const std::string & xPath) const
375
{
376
  std::vector<shared_ptr<XdmfItem> > toReturn;
377
  mImpl->readPathObjects(xPath, toReturn);
378
  return toReturn;
379 380
}

381 382 383 384 385 386
// C Wrappers

XDMFITEM *
XdmfCoreReaderRead(XDMFCOREREADER * reader, char * filePath, int * status)
{
  XDMF_ERROR_WRAP_START(status)
387 388 389
  shared_ptr<XdmfCoreReader> & refReader = *(shared_ptr<XdmfCoreReader> *)(reader);
  shared_ptr<XdmfItem> * p = new shared_ptr<XdmfItem>(refReader->read(filePath));
  return (XDMFITEM *) p;
390 391 392
  XDMF_ERROR_WRAP_END(status)
  return NULL;
}