/* * $Revision: 2565 $ * * last checkin: * $Author: gutwenger $ * $Date: 2012-07-07 17:14:54 +0200 (Sa, 07. Jul 2012) $ ***************************************************************/ /** \file * \brief Implementation of XML parser (class XmlParser) * (used for parsing and reading XML files) * * \author Sebastian Leipert * * \par License: * This file is part of the Open Graph Drawing Framework (OGDF). * * \par * Copyright (C)
* See README.txt in the root directory of the OGDF installation for details. * * \par * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * Version 2 or 3 as published by the Free Software Foundation; * see the file LICENSE.txt included in the packaging of this file * for details. * * \par * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * \par * You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * \see http://www.gnu.org/copyleft/gpl.html ***************************************************************/ #include "XmlParser.h" #include #include extern ofstream os; namespace ogdf { #define BUFFERLENGTH 8192 XmlParser::XmlParser(const char *fileName, bool doCheck) { // open file ifstream is(fileName, ios::in);// | ios::nocreate); // not accepted by gnu 3.02 if (!is) { setError("Cannot open file."); return; } createObjectTree(is, doCheck); } XmlParser::XmlParser(istream &is, bool doCheck) { createObjectTree(is,doCheck); } void XmlParser::createObjectTree(istream &is, bool doCheck) { initPredefinedKeys(); m_error = false; m_objectTree = 0; m_is = &is; m_doCheck = doCheck; // indicates more extensive checking // initialize line buffer (note: XML specifies a maximal line length // of 254 characters!) // See als the workaround for Get2Chip in function getLine() m_rLineBuffer = new char[BUFFERLENGTH]; // get2Chip special: // XML Standard: char[256]; *m_rLineBuffer = '\n'; m_lineBuffer = m_rLineBuffer+1; m_pCurrent = m_pStore = m_lineBuffer; m_cStore = 0; // forces getNextSymbol() to read first line m_keyName = 0; // create object tree m_objectTree = parseList(xmlEOF,xmlListEnd,""); delete[] m_rLineBuffer; } // we use predefined id constants for all relevant keys // this allows us to use efficient switch() statemnts in read() methods void XmlParser::initPredefinedKeys() { m_hashTable.fastInsert("NAME", namePredefKey); m_hashTable.fastInsert("GRAPH", graphPredefKey); m_hashTable.fastInsert("NODE", nodePredefKey); m_hashTable.fastInsert("TRANSITION",edgePredefKey); m_hashTable.fastInsert("EDGE", edgePredefKey); m_hashTable.fastInsert("POSITION", positionPredefKey); m_hashTable.fastInsert("X", xPredefKey); m_hashTable.fastInsert("Y", yPredefKey); m_hashTable.fastInsert("SIZE", sizePredefKey); m_hashTable.fastInsert("W", wPredefKey); m_hashTable.fastInsert("H", hPredefKey); m_hashTable.fastInsert("WIDTH", widthPredefKey); m_hashTable.fastInsert("HEIGHT", heightPredefKey); m_hashTable.fastInsert("NODETYPE", nodetypePredefKey); m_hashTable.fastInsert("EDGETYPE", edgetypePredefKey); m_hashTable.fastInsert("TYPE", typePredefKey); m_hashTable.fastInsert("FROM", sourcePredefKey); m_hashTable.fastInsert("SOURCE", sourcePredefKey); m_hashTable.fastInsert("TO", targetPredefKey); m_hashTable.fastInsert("TARGET", targetPredefKey); m_hashTable.fastInsert("SENSE", sensePredefKey); m_hashTable.fastInsert("PATH", pathPredefKey); // further keys get id's starting with NEXTPREDEFKEY m_num = NEXTPREDEFKEY; } XmlObject *XmlParser::parseList(XmlObjectType closingKey, XmlObjectType /* errorKey */, const char *objectBodyName) { XmlObject *firstSon = 0; XmlObject **pPrev = &firstSon; for( ; ; ) { XmlObjectType symbol = getNextSymbol(); if (symbol == closingKey || symbol == xmlError) return firstSon; XmlObject *object = 0; if (symbol == xmlListBegin) { symbol = getNextSymbol(); if (symbol != xmlKey) { setError("key expected"); return firstSon; } XmlKey key = m_keySymbol; object = OGDF_NEW XmlObject(key); size_t len = strlen(m_keyName)+1; char* newObjectBodyName = new char[len]; m_objectBody.pushBack(newObjectBodyName); ogdf::strcpy(newObjectBodyName,len,m_keyName); // Recursive call for building the tree. object->m_pFirstSon = parseList(xmlListEnd,xmlEOF,newObjectBodyName); } else if (m_eoTag) { // must be the body of an element if (symbol != xmlStringValue) { setError("String expected"); return firstSon; } size_t len = strlen(m_stringSymbol)+1; char *pChar = new char[len]; ogdf::strcpy(pChar,len,m_stringSymbol); object = OGDF_NEW XmlObject(hashString(objectBodyName),pChar); } else { // must be a symbol if (symbol != xmlKey) { setError("key expected"); return firstSon; } XmlKey key = m_keySymbol; symbol = getNextSymbol(); switch (symbol) { case xmlIntValue: object = OGDF_NEW XmlObject(key,m_intSymbol); break; case xmlDoubleValue: object = OGDF_NEW XmlObject(key,m_doubleSymbol); break; case xmlStringValue: { size_t len = strlen(m_stringSymbol)+1; char *pChar = new char[len]; ogdf::strcpy(pChar,len,m_stringSymbol); object = OGDF_NEW XmlObject(key,pChar); } break; case xmlListBegin: setError("unexpected begin of list"); break; case xmlListEnd: setError("unexpected end of list"); return firstSon; case xmlKey: setError("unexpected key"); return firstSon; case xmlEOF: setError("missing value"); return firstSon; case xmlError: return firstSon; } } *pPrev = object; pPrev = &object->m_pBrother; } return firstSon; } void XmlParser::destroyObjectList(XmlObject *object) { XmlObject *nextObject; for(; object; object = nextObject) { nextObject = object->m_pBrother; if (object->m_valueType == xmlStringValue) delete[] const_cast(object->m_stringValue); else if (object->m_valueType == xmlListBegin) destroyObjectList(object->m_pFirstSon); delete object; } } XmlParser::~XmlParser() { // we have to delete all objects and allocated char arrays in string values destroyObjectList(m_objectTree); while (!m_objectBody.empty()) delete[] m_objectBody.popFrontRet(); delete[] m_keyName; } bool XmlParser::getLine() { do { // Standard XML needs only this // if (m_is->eof()) return false; // m_is->getline(m_lineBuffer,255); // Workaround for Get2Chip. XML-Information may exceed 254 signs per line. // Moreover, XML signs may be longer than 254 signs. Cut information at '>'. // Workaround starts here. char c; int count = 0; while ( ((c = m_is->get() ) != '>') && (count <= (BUFFERLENGTH - 2))){ if (m_is->eof()) return false; m_lineBuffer[count++] = c; } if ( (c == '>') && (count <= (BUFFERLENGTH - 2))) m_lineBuffer[count++] = c; m_lineBuffer[count] = '\0'; // Workaround stops here. // Eat Whitespaces. for(m_pCurrent = m_lineBuffer; *m_pCurrent && isspace(*m_pCurrent); ++m_pCurrent) ; } while (*m_pCurrent == '#' || *m_pCurrent == 0); return true; } /***************************************************************************** getNextSymbol ******************************************************************************/ XmlObjectType XmlParser::getNextSymbol() { *m_pStore = m_cStore; m_eoTag = false; bool digit = false; // eat whitespace for(; *m_pCurrent && isspace(*m_pCurrent); ++m_pCurrent) ; if (*m_pCurrent == '>') { m_pCurrent++; m_eoTag = true; // end of a tag reached. } for(; *m_pCurrent && isspace(*m_pCurrent); ++m_pCurrent) ; // get new line if required if (*m_pCurrent == 0) { if (!getLine()) return xmlEOF; } // identify start of current symbol char *pStart = m_pCurrent; // we currently do not support strings with line breaks! if (*pStart == '=') { // attribute value // string or int or double expected // again: eat whitespace pStart++;m_pCurrent++; for(; *m_pCurrent && isspace(*m_pCurrent); ++m_pCurrent) ; // again: get new line if required if (*m_pCurrent == 0) { if (!getLine()) return xmlEOF; } // again: identify start of current symbol char *pStart = m_pCurrent; bool quotation = (*pStart == '\"' ? 1 : 0); if (quotation) { pStart++; m_pCurrent++; } if (*pStart == '-' || isdigit(*pStart)) // Check if int or double { digit = true; char *pCheck = m_pCurrent; pCheck++; while(isdigit(*pCheck)) ++pCheck; // int or double if (*pCheck == '.') pCheck++; // only double else if (quotation && *pCheck != '\"') digit = false; // must be string else if (!quotation && !isspace(*pCheck) && *pCheck != '>') digit = false; // must be string if (digit) { while(isdigit(*pCheck)) ++pCheck; if (quotation && *pCheck != '\"') digit = false; // must be string else if (!quotation && !isspace(*pCheck) && *pCheck != '>') digit = false; // must be string } } // if (!isdigit(*pStart) && (*pStart != '-')) { // string if (!digit) // string { m_stringSymbol = m_pCurrent; if (quotation){ for(; *m_pCurrent != 0 && *m_pCurrent != '\"'; ++m_pCurrent) if (*m_pCurrent == '\\') ++m_pCurrent; // No quotation mark found yet. Drop the line. } else { for(; *m_pCurrent != 0 && !isspace(*m_pCurrent) && *m_pCurrent != '>'; ++m_pCurrent) if (*m_pCurrent == '\\') ++m_pCurrent; } if (quotation && *m_pCurrent == 0) { m_longString = (pStart); while(getLine()) { for(m_pCurrent = m_lineBuffer; *m_pCurrent != 0 && *m_pCurrent != '\"'; ++m_pCurrent) if (*m_pCurrent == '\\') ++m_pCurrent; if (*m_pCurrent == 0) m_longString += m_lineBuffer; else { m_cStore = *(m_pStore = m_pCurrent); *m_pCurrent++ = 0; // Drop quotation mark. m_longString += m_lineBuffer; break; } } m_stringSymbol = m_longString.cstr(); } else { m_cStore = *(m_pStore = m_pCurrent); if (quotation) *m_pCurrent++ = 0; // Drop quotation mark. else *m_pCurrent = 0; } return xmlStringValue; } // else if (*pStart == '-' || isdigit(*pStart)) else // int or double { m_pCurrent++; while(isdigit(*m_pCurrent)) ++m_pCurrent; if (*m_pCurrent == '.') // double { // check to be done sscanf(pStart,"%lf",&m_doubleSymbol); m_pCurrent++; while (isdigit(*m_pCurrent)) ++m_pCurrent; if (quotation){ for(; *m_pCurrent != 0 && *m_pCurrent != '\"' && isdigit(*m_pCurrent); ++m_pCurrent) ; if (*m_pCurrent == '\"') m_pCurrent++; else { setError("malformed number"); return xmlError; } } return xmlDoubleValue; } else // int { if (isalpha(*m_pCurrent)) { setError("malformed number"); return xmlError; } if (quotation){ for(; *m_pCurrent != 0 && *m_pCurrent != '\"'; ++m_pCurrent); if (*m_pCurrent == '\"') m_pCurrent++; else{ setError("malformed number"); return xmlError; } } sscanf(pStart,"%d",&m_intSymbol); return xmlIntValue; } } } if (*pStart == '<') { //check if end of list m_pCurrent++; for (; *m_pCurrent && isspace(*m_pCurrent); ++m_pCurrent); if (*m_pCurrent == '/'){ for (; *m_pCurrent && *m_pCurrent != '>'; ++m_pCurrent); m_cStore = *(m_pStore = m_pCurrent); return xmlListEnd; } else { m_cStore = *(m_pStore = m_pCurrent); return xmlListBegin; } } else if (*pStart == '/') { m_pCurrent++; for (; *m_pCurrent && *m_pCurrent == '>'; ++m_pCurrent); m_cStore = *(m_pStore = m_pCurrent); return xmlListEnd; } else // Invalid clause: if(isalpha(*pStart)). May contain numbers { // Tag name, Attribute Name (both are said to be keys) // or body name (element) // check if really a correct key (error if not) if (m_doCheck) { m_pCurrent++; for (;*m_pCurrent; ++m_pCurrent) if (!(isalpha(*m_pCurrent) || isdigit(*m_pCurrent))) { setError("malformed key"); return xmlError; } } if (m_eoTag) // its the body of an element { // Do not ignore whitespace, quotation marks etc. // They belong to the element. // Only search for the '<' of the next tag. // The element is considered as string. // Get new line if required if (*m_pCurrent == 0) { if (!getLine()) return xmlEOF; } // again: identify start of current symbol //char *pStart = m_pCurrent; m_stringSymbol = m_pCurrent; while(*m_pCurrent != 0 && *m_pCurrent != '<' ) ++m_pCurrent; m_cStore = *(m_pStore = m_pCurrent); *m_pCurrent = 0; return xmlStringValue; } else // it is a key { while(*m_pCurrent != 0 && *m_pCurrent != '=' && *m_pCurrent != '>' && *m_pCurrent != '/' && *m_pCurrent != '<' && !isspace(*m_pCurrent) ) ++m_pCurrent; m_cStore = *(m_pStore = m_pCurrent); *m_pCurrent = 0; if (m_keyName != 0) delete[] m_keyName; size_t len = strlen(pStart)+6; m_keyName = new char[len]; ogdf::strcpy(m_keyName,len,pStart); m_keySymbol = hashString(pStart); return xmlKey; } } // //setError("unknown symbol"); //return xmlError; } XmlKey XmlParser::hashString(const String &str) { XmlKey key = m_hashTable.insertByNeed(str,-1); if(key->info() == -1) key->info() = m_num++; return key; } /***************************************************************************** getNodeIdRange ******************************************************************************/ XmlObject *XmlParser::getNodeIdRange(int &minId,int &maxId, int &nodetypeCount, XmlObject *graphObject) { nodetypeCount = minId = maxId = -1; if (graphObject == 0) graphObject = m_objectTree; XmlObject *scanObject = graphObject; for(; scanObject; scanObject = scanObject->m_pBrother) if (id(scanObject) == graphPredefKey) break; if (!scanObject || id(scanObject) != graphPredefKey) { scanObject = graphObject; for(; scanObject; scanObject = scanObject->m_pBrother) { graphObject = getNodeIdRange(minId,maxId,nodetypeCount,scanObject->m_pFirstSon); if (graphObject && id(graphObject) == graphPredefKey) return graphObject; } } if (!scanObject || scanObject->m_valueType != xmlListBegin) return 0; XmlObject *son = scanObject->m_pFirstSon; for(; son; son = son->m_pBrother) { if (id(son) == nodePredefKey && son->m_valueType == xmlListBegin) maxId++; else if (id(son) == nodetypePredefKey && son->m_valueType == xmlListBegin) nodetypeCount++; } if (maxId >= 0) minId = 0; return scanObject; } /***************************************************************************** makeIdMap ******************************************************************************/ bool XmlParser::makeIdMap( int maxId, Array & idMap, int nodetypeCount, Array & typeName, Array & typeWidth, Array & typeHeight, XmlObject *graphObject) { int idCount = 0; int typeCount = 0; for(; graphObject; graphObject = graphObject->m_pBrother) if (id(graphObject) == graphPredefKey) break; if (!graphObject || graphObject->m_valueType != xmlListBegin) return 0; XmlObject *son = graphObject->m_pFirstSon; for(; son; son = son->m_pBrother) { if (id(son) == nodePredefKey && son->m_valueType == xmlListBegin) { XmlObject *nodeSon = son->m_pFirstSon; for(; nodeSon; nodeSon = nodeSon->m_pBrother) if (id(nodeSon) == namePredefKey && nodeSon->m_valueType == xmlStringValue){ if (idCount >= maxId+1) return 0; size_t len = strlen(nodeSon->m_stringValue)+1; idMap[idCount] = new char[len]; ogdf::strcpy(idMap[idCount++],len,nodeSon->m_stringValue); } } else if (id(son) == nodetypePredefKey && son->m_valueType == xmlListBegin){ XmlObject *nodeSon = son->m_pFirstSon; if (typeCount <= nodetypeCount){ for(; nodeSon; nodeSon = nodeSon->m_pBrother) { if (id(nodeSon) == namePredefKey && nodeSon->m_valueType == xmlStringValue){ size_t len = strlen(nodeSon->m_stringValue)+1; typeName[typeCount] = new char[len]; ogdf::strcpy(typeName[typeCount],len,nodeSon->m_stringValue); } else if (id(nodeSon) == widthPredefKey ){ if (nodeSon->m_valueType == xmlIntValue) typeWidth[typeCount] = (int) nodeSon->m_intValue; else if (nodeSon->m_valueType == xmlDoubleValue) typeWidth[typeCount] = nodeSon->m_doubleValue; } else if (id(nodeSon) == heightPredefKey ){ if (nodeSon->m_valueType == xmlIntValue) typeHeight[typeCount] = (int) nodeSon->m_intValue; else if (nodeSon->m_valueType == xmlDoubleValue) typeHeight[typeCount] = nodeSon->m_doubleValue; } } typeCount++; } } } if (idCount != maxId+1) return 0; else return 1; } /***************************************************************************** read ******************************************************************************/ bool XmlParser::read(Graph &G) { G.clear(); int minId, maxId, nodetypeCount; XmlObject *graphObject = getNodeIdRange(minId, maxId, nodetypeCount,0); //cout << endl << minId << " " << maxId << endl; if (!graphObject) { setError("missing graph key"); return false; } Array typeWidth(0,nodetypeCount,0); Array typeHeight(0,nodetypeCount,0); Array typeName(nodetypeCount+1); Array idMap(maxId+1); if (!makeIdMap(maxId,idMap,nodetypeCount,typeName,typeWidth,typeHeight,graphObject)) { setError("wrong name identifier"); return false; } Array mapToNode(minId,maxId,0); int notDefined = minId-1; //indicates not defined id key int idCount = minId; XmlObject *son = graphObject->m_pFirstSon; for(; son; son = son->m_pBrother) { switch(id(son)) { case nodePredefKey: { if (son->m_valueType != xmlListBegin) break; // set attributes to default values int vId = idCount++; // create new node if necessary and assign attributes if (mapToNode[vId] == 0) mapToNode[vId] = G.newNode(); break; } case edgePredefKey: if (son->m_valueType != xmlListBegin) break; // set attributes to default values int sourceId = notDefined, targetId = notDefined; // read all relevant attributes XmlObject *edgeSon = son->m_pFirstSon; for(; edgeSon; edgeSon = edgeSon->m_pBrother) { int i = 0; switch(id(edgeSon)) { case sourcePredefKey: if (edgeSon->m_valueType != xmlStringValue) break; for (i = 0; i<= maxId;i++) if (!strcmp(idMap[i],edgeSon->m_stringValue)) sourceId = i; break; case targetPredefKey: if (edgeSon->m_valueType != xmlStringValue) break; for (i = 0; i<= maxId;i++) if (!strcmp(idMap[i],edgeSon->m_stringValue)) targetId = i; break; } } // check if everything required is defined correctly if (sourceId == notDefined || targetId == notDefined) { setError("source or target id not defined"); //cout << "source or target id not defined" << endl; return false; } else if (sourceId < minId || maxId < sourceId || targetId < minId || maxId < targetId) { setError("source or target id out of range"); //cout << "source or target id out of range" << endl; return false; } // create adjacent nodes if necessary and new edge if (mapToNode[sourceId] == 0) mapToNode[sourceId] = G.newNode(); if (mapToNode[targetId] == 0) mapToNode[targetId] = G.newNode(); G.newEdge(mapToNode[sourceId],mapToNode[targetId]); break; } } return true; } /***************************************************************************** read ******************************************************************************/ bool XmlParser::read(Graph &G, GraphAttributes &AG) { OGDF_ASSERT(&G == &(const Graph &)AG) G.clear(); int minId, maxId, nodetypeCount; XmlObject *graphObject = getNodeIdRange(minId, maxId, nodetypeCount,0); if (!graphObject) { setError("missing graph key"); return false; } Array typeWidth(0,nodetypeCount,0); Array typeHeight(0,nodetypeCount,0); Array typeName(nodetypeCount+1); Array idMap(maxId+1); if (!makeIdMap(maxId,idMap,nodetypeCount,typeName,typeWidth,typeHeight,graphObject)) { setError("wrong name identifier"); closeLabels(idMap,typeName); return false; } Array mapToNode(minId,maxId,0); int notDefined = minId-1; //indicates not defined id key int idCount = minId; DPolyline bends; String label; XmlObject *son = graphObject->m_pFirstSon; for(; son; son = son->m_pBrother) { switch(id(son)) { case nodePredefKey: { if (son->m_valueType != xmlListBegin) break; // set attributes to default values int vId = idCount++;; double x = 0, y = 0, w = 0, h = 0; bool typeDefined = 0; // read all relevant attributes XmlObject *graphicsObject = son->m_pFirstSon; for(; graphicsObject; graphicsObject = graphicsObject->m_pBrother) { switch(id(graphicsObject)) { case namePredefKey: if (graphicsObject->m_valueType == xmlStringValue) label = graphicsObject->m_stringValue; break; case xPredefKey: if(graphicsObject->m_valueType == xmlDoubleValue) x = graphicsObject->m_doubleValue; else if (graphicsObject->m_valueType == xmlIntValue) x = (int) graphicsObject->m_intValue; break; case yPredefKey: if(graphicsObject->m_valueType == xmlDoubleValue) y = graphicsObject->m_doubleValue; else if (graphicsObject->m_valueType == xmlIntValue) y = (int) graphicsObject->m_intValue; break; case wPredefKey: if (!typeDefined) { if(graphicsObject->m_valueType == xmlDoubleValue) w = graphicsObject->m_doubleValue; else if (graphicsObject->m_valueType == xmlIntValue) w = (int) graphicsObject->m_intValue; } break; case hPredefKey: if (!typeDefined) { if(graphicsObject->m_valueType == xmlDoubleValue) h = graphicsObject->m_doubleValue; else if (graphicsObject->m_valueType == xmlIntValue) h = (int) graphicsObject->m_intValue; } break; case widthPredefKey: if (!typeDefined) { if(graphicsObject->m_valueType == xmlDoubleValue) w = graphicsObject->m_doubleValue; else if (graphicsObject->m_valueType == xmlIntValue) w = (int) graphicsObject->m_intValue; } break; case heightPredefKey: if (!typeDefined) { if(graphicsObject->m_valueType == xmlDoubleValue) h = graphicsObject->m_doubleValue; else if (graphicsObject->m_valueType == xmlIntValue) h = (int) graphicsObject->m_intValue; } break; case typePredefKey: if(graphicsObject->m_valueType == xmlStringValue) { int i = 0; for (;i <= nodetypeCount && strcmp(typeName[i],graphicsObject->m_stringValue);i++); if (i <= nodetypeCount) { w = typeWidth[i]; h = typeHeight[i]; typeDefined = 1; } } break; case positionPredefKey: { if (graphicsObject->m_valueType != xmlListBegin) break; XmlObject *graphicsObjectElement = graphicsObject->m_pFirstSon; for(; graphicsObjectElement; graphicsObjectElement = graphicsObjectElement->m_pBrother) { switch(id(graphicsObjectElement)) { case xPredefKey: if(graphicsObjectElement->m_valueType == xmlDoubleValue) x = graphicsObjectElement->m_doubleValue; else if (graphicsObjectElement->m_valueType == xmlIntValue) x = (int) graphicsObjectElement->m_intValue; break; case yPredefKey: if(graphicsObjectElement->m_valueType == xmlDoubleValue) y = graphicsObjectElement->m_doubleValue; else if (graphicsObjectElement->m_valueType == xmlIntValue) y = (int) graphicsObjectElement->m_intValue; break; }// switch(id(graphicsObjectElement)) }// for(; graphicsObjectElement; graphicsObjectElement = graphicsObjectElement->m_pBrother) break; }// case positionPredefKey: case sizePredefKey: { if (graphicsObject->m_valueType != xmlListBegin) break; XmlObject *graphicsObjectElement = graphicsObject->m_pFirstSon; for(; graphicsObjectElement; graphicsObjectElement = graphicsObjectElement->m_pBrother) { switch(id(graphicsObjectElement)) { case wPredefKey: if (!typeDefined) { if(graphicsObjectElement->m_valueType == xmlDoubleValue) w = graphicsObjectElement->m_doubleValue; else if (graphicsObjectElement->m_valueType == xmlIntValue) w = (int) graphicsObjectElement->m_intValue; } break; case hPredefKey: if (!typeDefined) { if(graphicsObjectElement->m_valueType == xmlDoubleValue) h = graphicsObjectElement->m_doubleValue; else if (graphicsObjectElement->m_valueType == xmlIntValue) h = (int) graphicsObjectElement->m_intValue; } break; case widthPredefKey: if (!typeDefined) { if(graphicsObjectElement->m_valueType == xmlDoubleValue) w = graphicsObjectElement->m_doubleValue; else if (graphicsObjectElement->m_valueType == xmlIntValue) w = (int) graphicsObjectElement->m_intValue; } break; case heightPredefKey: if (!typeDefined) { if(graphicsObjectElement->m_valueType == xmlDoubleValue) h = graphicsObjectElement->m_doubleValue; else if (graphicsObjectElement->m_valueType == xmlIntValue) h = (int) graphicsObjectElement->m_intValue; } break; }// switch(id(graphicsObjectElement)) }// for(; graphicsObjectElement; graphicsObjectElement = graphicsObjectElement->m_pBrother) break; }// case sizePredefKey: }// switch(id(graphicsObject)) }// for(; graphicsObject; graphicsObject = graphicsObject->m_pBrother) // create new node if necessary and assign attributes if (mapToNode[vId] == 0) mapToNode[vId] = G.newNode(); AG.x(mapToNode[vId]) = x; AG.y(mapToNode[vId]) = y; if (w > 0) //skip negative width AG.width (mapToNode[vId]) = w; if (h > 0) // skip negative height AG.height(mapToNode[vId]) = h; AG.labelNode(mapToNode[vId]) = label; break; }// case nodePredefKey: case edgePredefKey: { if (son->m_valueType != xmlListBegin) break; // set attributes to default values int sourceId = notDefined, targetId = notDefined; bool backward = false; // read all relevant attributes XmlObject *graphicsObject = son->m_pFirstSon; for(; graphicsObject; graphicsObject = graphicsObject->m_pBrother) { int i = 0; switch(id(graphicsObject)) { case namePredefKey: if (graphicsObject->m_valueType == xmlStringValue) label = graphicsObject->m_stringValue; break; case sourcePredefKey: if (graphicsObject->m_valueType != xmlStringValue) break; for (i = 0; i<= maxId;i++) if (!strcmp(idMap[i],graphicsObject->m_stringValue)) sourceId = i; break; case targetPredefKey: if (graphicsObject->m_valueType != xmlStringValue) break; for (i = 0; i<= maxId;i++) if (!strcmp(idMap[i],graphicsObject->m_stringValue)) targetId = i; break; case sensePredefKey: if (graphicsObject->m_valueType != xmlStringValue) break; if (!strcmp("BACKWARD",graphicsObject->m_stringValue)) backward = true; case pathPredefKey: { if (graphicsObject->m_valueType != xmlListBegin) break; DPoint dp; XmlObject *graphicsObjectElement = graphicsObject->m_pFirstSon; for(; graphicsObjectElement; graphicsObjectElement = graphicsObjectElement->m_pBrother) { switch(id(graphicsObjectElement)) { case positionPredefKey: { if (graphicsObjectElement->m_valueType != xmlListBegin) break; DPoint dp; XmlObject *element = graphicsObjectElement->m_pFirstSon; for(; element; element = element->m_pBrother) { switch(id(element)) { case xPredefKey: if(element->m_valueType == xmlDoubleValue) dp.m_x = element->m_doubleValue; else if (element->m_valueType == xmlIntValue) dp.m_x = (int) element->m_intValue; break; case yPredefKey: if(element->m_valueType == xmlDoubleValue) dp.m_y = element->m_doubleValue; else if (element->m_valueType == xmlIntValue) dp.m_y = (int) element->m_intValue; break; }// switch(id(element)) }// for(; element; element = element->m_pBrother) bends.pushBack(dp); break; }// case positionPredefKey: }//switch(id(graphicsObjectElement)) }//for(; graphicsObjectElement; graphicsObjectElement = graphicsObjectElement->m_pBrother) break; }// case positionPredefKey: /* case graphicsPredefKey: if (graphicsObject->m_valueType != xmlListBegin) break; XmlObject *graphicsObject = graphicsObject->m_pFirstSon; for(; graphicsObject; graphicsObject = graphicsObject->m_pBrother) { if(id(graphicsObject) == LinePredefKey && graphicsObject->m_valueType == xmlListBegin) readLineAttribute(graphicsObject->m_pFirstSon,bends); } */ }// switch(id(graphicsObject)) }// for(; graphicsObject; graphicsObject = graphicsObject->m_pBrother) // check if everything required is defined correctly if (sourceId == notDefined || targetId == notDefined) { setError("source or target id not defined"); closeLabels(idMap,typeName); return false; } else if (sourceId < minId || maxId < sourceId || targetId < minId || maxId < targetId) { setError("source or target id out of range"); closeLabels(idMap,typeName); return false; } // create adjacent nodes if necessary and new edge if (mapToNode[sourceId] == 0) mapToNode[sourceId] = G.newNode(); if (mapToNode[targetId] == 0) mapToNode[targetId] = G.newNode(); edge e; if (backward) e = G.newEdge(mapToNode[targetId],mapToNode[sourceId]); else e = G.newEdge(mapToNode[sourceId],mapToNode[targetId]); AG.labelEdge(e) = label; AG.bends(e).conc(bends); break; }// case edgePredefKey: }// switch(id(son)) { } closeLabels(idMap,typeName); return true; } void XmlParser::closeLabels(Array idMap, Array typeName) { int i; for (i = idMap.low(); i <= idMap.high();i++) if (idMap[i]) delete[] idMap[i]; for (i = typeName.low(); i <= typeName.high();i++) if (typeName[i]) delete[] typeName[i]; } void XmlParser::readLineAttribute(XmlObject *object, DPolyline &dpl) { dpl.clear(); for(; object; object = object->m_pBrother) { if (id(object) == pointPredefKey && object->m_valueType == xmlListBegin) { DPoint dp; XmlObject *pointObject = object->m_pFirstSon; for (; pointObject; pointObject = pointObject->m_pBrother) { if (pointObject->m_valueType != xmlDoubleValue) continue; if (id(pointObject) == xPredefKey) dp.m_x = pointObject->m_doubleValue; else if (id(pointObject) == yPredefKey) dp.m_y = pointObject->m_doubleValue; } dpl.pushBack(dp); } } } void XmlParser::setError(const char *errorString) { m_error = true; m_errorString = errorString; } void XmlParser::indent(ostream &os, int d) { for(int i = 1; i <= d; ++i) os << " "; } /* void XmlParser::output(ostream &os, XmlObject *object, int d) { for(; object; object = object->m_pBrother) { indent(os,d); os << object->m_key->key(); switch(object->m_valueType) { case xmlIntValue: os << " " << object->m_intValue << "\n"; break; case xmlDoubleValue: os << " " << object->m_doubleValue << "\n"; break; case xmlStringValue: os << " \"" << object->m_stringValue << "\"\n"; break; case xmlListBegin: os << "\n"; output(os, object->m_pFirstSon, d+2); break; } } } */ } // end namespace ogdf