XdmfCoreReader.cpp 10 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
#include <libxml/uri.h>
25
#include <libxml/xpointer.h>
26
#include <libxml/xmlreader.h>
27
#include <map>
28
#include <sstream>
29
#include <cstring>
30 31 32
#include "XdmfCoreItemFactory.hpp"
#include "XdmfCoreReader.hpp"
#include "XdmfItem.hpp"
33
#include "XdmfSystemUtils.hpp"
34
#include "XdmfError.hpp"
35

36 37
#include <fstream>

38 39 40 41 42 43 44
/**
 * PIMPL
 */
class XdmfCoreReader::XdmfCoreReaderImpl {

public:

45
  XdmfCoreReaderImpl(const shared_ptr<const XdmfCoreItemFactory> itemFactory,
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
                     const XdmfCoreReader * const coreReader) :
    mCoreReader(coreReader),
    mItemFactory(itemFactory)
  {
  };

  ~XdmfCoreReaderImpl()
  {
  };

  void
  closeFile()
  {
    mXPathMap.clear();
    xmlXPathFreeContext(mXPathContext);
    xmlFreeDoc(mDocument);
    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);
    }

    mDocument = xmlReadFile(filePath.c_str(), NULL, 0);

    if(mDocument == NULL) {
77 78 79
      XdmfError::message(XdmfError::FATAL,
                         "xmlReadFile could not read " + filePath +
                         " in XdmfCoreReader::XdmfCoreReaderImpl::openFile");
80 81 82 83 84 85
    }

    mXPathContext = xmlXPtrNewContext(mDocument, NULL, NULL);
    mXPathMap.clear();
  }

86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
  void
  parse(const std::string & lightData) 
  {
    mDocument = xmlParseDoc((const xmlChar*)lightData.c_str());
                               
    if(mDocument == NULL) {
      XdmfError::message(XdmfError::FATAL,
                         "xmlReadFile could not parse passed light data string"
                         " in XdmfCoreReader::XdmfCoreReaderImpl::parse");
    }

    mXPathContext = xmlXPtrNewContext(mDocument, NULL, NULL);
    mXPathMap.clear();
  }

101 102 103 104 105
  /**
   * Constructs XdmfItems for all nodes in currNode's tree.
   * XdmfItems are constructed by recursively calling this function for all
   * children of currNode.
   */
106
  std::vector<shared_ptr<XdmfItem> >
107 108
  read(xmlNodePtr currNode)
  {
109
    std::vector<shared_ptr<XdmfItem> > myItems;
110 111 112 113 114

    while(currNode != NULL) {
      if(currNode->type == XML_ELEMENT_NODE) {
        if(xmlStrcmp(currNode->name, (xmlChar*)"include") == 0) {
          // Deal with proper reading of XIncludes
115 116 117 118

          xmlChar * xpointer = NULL;
          xmlChar * href = NULL;

119 120 121 122 123
          xmlAttrPtr currAttribute = currNode->properties;
          while(currAttribute != NULL) {
            if(xmlStrcmp(currAttribute->name, (xmlChar*)"xpointer") == 0) {
              xpointer = currAttribute->children->content;
            }
124 125 126 127 128 129 130 131 132 133 134 135
            if(xmlStrcmp(currAttribute->name, (xmlChar*)"href") == 0) {
              href = currAttribute->children->content;
            }
            currAttribute = currAttribute->next;
          }

          xmlDocPtr document = NULL;
          xmlXPathContextPtr context = mXPathContext;
          if(href) {
            xmlChar * filePath = xmlBuildURI(href, mDocument->URL);
            document = xmlReadFile((char*)filePath, NULL, 0);
            context = xmlXPtrNewContext(document, NULL, NULL);           
136
          }
137

138
          if(xpointer) {
139 140 141 142
            xmlXPathObjectPtr result = xmlXPtrEval(xpointer, context);
            if(result && !xmlXPathNodeSetIsEmpty(result->nodesetval)) {
              for(int i=0; i<result->nodesetval->nodeNr; ++i) {
                this->readSingleNode(result->nodesetval->nodeTab[i],
143 144 145
                                     myItems);
              }
            }
146 147 148 149 150 151
            xmlXPathFreeObject(result);
          }

          if(href) {
            xmlXPathFreeContext(context);
            xmlFreeDoc(document);
152
          }
153

154 155 156 157 158 159 160 161
        }
        else {
          // Normal reading
          this->readSingleNode(currNode, myItems);
        }
      }
      currNode = currNode->next;
    }
162

163 164 165 166 167 168 169 170 171 172
    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,
173
                 std::vector<shared_ptr<XdmfItem> > & myItems)
174
  {
175
    std::map<xmlNodePtr, shared_ptr<XdmfItem> >::const_iterator iter =
176 177 178 179 180 181
      mXPathMap.find(currNode);
    if(iter != mXPathMap.end()) {
      myItems.push_back(iter->second);
    }
    else {
      std::map<std::string, std::string> itemProperties;
182 183 184

      xmlNodePtr childNode = currNode->children;
      while(childNode != NULL) {
185 186 187 188
        if(childNode->type == XML_TEXT_NODE && childNode->content) {
          const char * content = (char*)childNode->content;

          // determine if content is whitespace
189
          const size_t contentSize = std::strlen(content);
190 191
          bool whitespace = true;

192
          for(size_t i=0; i<contentSize; ++i) {
193 194 195 196 197 198 199 200 201 202 203
            if(!isspace(content[i])) {
              whitespace = false;
              break;
            }
          }

          if(!whitespace) {
            itemProperties["Content"] = content;
            itemProperties["XMLDir"] = mXMLDir;
            break;
          }
204 205
        }
        childNode = childNode->next;
206 207 208 209 210 211 212 213
      }
      xmlAttrPtr currAttribute = currNode->properties;
      while(currAttribute != NULL) {
        itemProperties[(const char *)currAttribute->name] =
          (const char *)currAttribute->children->content;
        currAttribute = currAttribute->next;
      }

214
      std::vector<shared_ptr<XdmfItem> > childItems =
215
        this->read(currNode->children);
216
      shared_ptr<XdmfItem> newItem =
217 218 219 220
        mItemFactory->createItem((const char *)currNode->name,
                                 itemProperties,
                                 childItems);
      if(newItem == NULL) {
221 222 223
        XdmfError::message(XdmfError::FATAL, 
                           "mItemFactory failed to createItem in "
                           "XdmfCoreReader::XdmfCoreReaderImpl::readSingleNode");
224 225 226 227 228 229 230 231 232 233
      }

      newItem->populateItem(itemProperties, childItems, mCoreReader);
      myItems.push_back(newItem);
      mXPathMap[currNode] = newItem;
    }
  }

  void
  readPathObjects(const std::string & xPath,
234
                  std::vector<shared_ptr<XdmfItem> > & myItems)
235 236 237 238 239 240 241 242 243 244 245 246 247
  {
    xmlXPathObjectPtr xPathObject =
      xmlXPathEvalExpression((xmlChar*)xPath.c_str(), mXPathContext);
    if(xPathObject && xPathObject->nodesetval) {
      for(int i=0; i<xPathObject->nodesetval->nodeNr; ++i) {
        this->readSingleNode(xPathObject->nodesetval->nodeTab[i], myItems);
      }
    }
    xmlXPathFreeObject(xPathObject);
  }

  xmlDocPtr mDocument;
  const XdmfCoreReader * const mCoreReader;
248
  const shared_ptr<const XdmfCoreItemFactory> mItemFactory;
249
  const std::string mRootItemTag;
250 251
  std::string mXMLDir;
  xmlXPathContextPtr mXPathContext;
252
  std::map<xmlNodePtr, shared_ptr<XdmfItem> > mXPathMap;
253 254
};

255
XdmfCoreReader::XdmfCoreReader(const shared_ptr<const XdmfCoreItemFactory> itemFactory) :
256
  mImpl(new XdmfCoreReaderImpl(itemFactory, this))
257 258 259 260 261
{
}

XdmfCoreReader::~XdmfCoreReader()
{
262
  delete mImpl;
263 264
}

265 266 267 268 269 270 271 272 273 274 275
shared_ptr<XdmfItem >
XdmfCoreReader::parse(const std::string & lightData) const
{
  mImpl->parse(lightData);
  const xmlNodePtr currNode = xmlDocGetRootElement(mImpl->mDocument);
  const std::vector<shared_ptr<XdmfItem> > toReturn =
    mImpl->read(currNode->children);
  mImpl->closeFile();
  return(toReturn[0]);
}

276
std::vector<shared_ptr<XdmfItem> >
277
XdmfCoreReader::readItems(const std::string & filePath) const
278
{
279 280
  mImpl->openFile(filePath);
  const xmlNodePtr currNode = xmlDocGetRootElement(mImpl->mDocument);
281
  const std::vector<shared_ptr<XdmfItem> > toReturn =
282 283 284
    mImpl->read(currNode->children);
  mImpl->closeFile();
  return toReturn;
285 286
}

287
shared_ptr<XdmfItem>
288
XdmfCoreReader::read(const std::string & filePath) const
289
{
290
  const std::vector<shared_ptr<XdmfItem> > toReturn = readItems(filePath);
291
  if (toReturn.size() == 0) {
292
    return(shared_ptr<XdmfItem>());
293 294
  }
  return(toReturn[0]);
295
}
296

297
std::vector<shared_ptr<XdmfItem> >
298 299
XdmfCoreReader::read(const std::string & filePath,
                     const std::string & xPath) const
300
{
301
  mImpl->openFile(filePath);
302
  std::vector<shared_ptr<XdmfItem> > toReturn = this->readPathObjects(xPath);
303 304
  mImpl->closeFile();
  return toReturn;
305
}
306

307
std::vector<shared_ptr<XdmfItem> >
308
XdmfCoreReader::readPathObjects(const std::string & xPath) const
309
{
310
  std::vector<shared_ptr<XdmfItem> > toReturn;
311 312
  mImpl->readPathObjects(xPath, toReturn);
  return toReturn;
313 314
}