bool GraphMLParser::readData( GraphAttributes &GA, const node &v, const XmlTagObject &nodeData) { XmlAttributeObject *keyId; nodeData.findXmlAttributeObjectByName("key", keyId); if(keyId == NULL) { cerr << "ERROR: Node data does not have a key.\n"; return false; } const long attrs = GA.attributes(); std::stringstream value(nodeData.getValue()); switch (graphml::toAttribute(m_attrName[keyId->getValue()])) { case graphml::a_nodeLabel: if(attrs & GraphAttributes::nodeLabel) { value >> GA.label(v); } break; case graphml::a_x: if(attrs & GraphAttributes::nodeGraphics) { value >> GA.x(v); }
static inline bool readColor(Color &color, const XmlTagObject &tag) { XmlAttributeObject *redAttr, *greenAttr, *blueAttr, *alphaAttr; tag.findXmlAttributeObjectByName("red", redAttr); tag.findXmlAttributeObjectByName("green", greenAttr); tag.findXmlAttributeObjectByName("blue", blueAttr); tag.findXmlAttributeObjectByName("alpha", alphaAttr); if(!redAttr || !greenAttr || !blueAttr) { OGDF_ERROR("Missing compound attrribute on color tag " << "(line " << tag.getLine() << ")."); return false; } int compound; std::istringstream is; is.clear(); is.str(redAttr->getValue()); is >> compound; color.red(static_cast<uint8_t>(compound)); is.clear(); is.str(greenAttr->getValue()); is >> compound; color.green(static_cast<uint8_t>(compound)); is.clear(); is.str(blueAttr->getValue()); is >> compound; color.blue(static_cast<uint8_t>(compound)); if(alphaAttr) { is.clear(); is.str(alphaAttr->getValue()); is >> compound; color.alpha(static_cast<uint8_t>(compound)); } return true; }
static inline bool readVizAttribute( GraphAttributes &GA, node v, const XmlTagObject &tag) { const long attrs = GA.attributes(); if(tag.getName() == "viz:position") { if(attrs & GraphAttributes::nodeGraphics) { XmlAttributeObject *xAttr, *yAttr, *zAttr; tag.findXmlAttributeObjectByName("x", xAttr); tag.findXmlAttributeObjectByName("y", yAttr); tag.findXmlAttributeObjectByName("z", zAttr); if(!xAttr || !yAttr) { OGDF_ERROR("Missing \"x\" or \"y\" on position tag " << "(line " << tag.getLine() << ")."); return false; } std::istringstream is; is.clear(); is.str(xAttr->getValue()); is >> GA.x(v); is.clear(); is.str(yAttr->getValue()); is >> GA.y(v); // z attribute is optional and avaliable only in \a threeD mode. if(zAttr && (attrs & GraphAttributes::threeD)) { is.clear(); is.str(zAttr->getValue()); is >> GA.z(v); } }
bool Parser::readCluster( Graph &G, ClusterGraph &C, ClusterGraphAttributes *CA, cluster rootCluster, const XmlTagObject &rootTag) { List<XmlTagObject *> nodeTags; rootTag.findSonXmlTagObjectByName("node", nodeTags); for(XmlTagObject *obj : nodeTags) { const XmlTagObject &nodeTag = *obj; XmlAttributeObject *idAttr; nodeTag.findXmlAttributeObjectByName("id", idAttr); if(!idAttr) { OGDF_ERROR("node is missing an attribute " << "(line " << nodeTag.getLine() << ")."); } // Node is a cluster iff it contains other nodes. XmlTagObject *nodesTag; nodeTag.findSonXmlTagObjectByName("nodes", nodesTag); if(nodesTag) { // Node tag found, therefore it is a cluster. const cluster c = C.newCluster(rootCluster); m_clusterId[idAttr->getValue()] = c; if(!readCluster(G, C, CA, c, *nodesTag)) { return false; } } else { // Node tag not found, therefore it is "normal" node. const node v = G.newNode(); C.reassignNode(v, rootCluster); m_nodeId[idAttr->getValue()] = v; if(CA) { readAttributes(*CA, v, nodeTag); } } } return true; }
// // p a r s e // // Take a look at the state machine of parse() to understand // what is going on here. // // TODO: It seems to be useful that this function throws an exception // if something goes wrong. XmlTagObject *XmlParser::parse() { // Increment recursion depth ++m_recursionDepth; // currentTagObject is the tag object we want to create // in this invocation of parse() XmlTagObject *currentTagObject = 0; // Now we are in the start state of the state machine for( ; ; ) { XmlToken token = m_pScanner->getNextToken(); // Expect "<", otherwise failure if (token != openingBracket) { reportError("XmlParser::parse", __LINE__, "Opening Bracket expected!", getInputFileLineCounter()); } // Let's look what comes after "<" token = m_pScanner->getNextToken(); // Read "?", i.e. we have the XML header line <? ... ?> if (token == questionMark) { // Skip until we reach the matching question mark if (!m_pScanner->skipUntil('?')) { reportError("XmlParser::parse", __LINE__, "Could not found the matching '?'", getInputFileLineCounter()); } // Consume ">", otherwise failure token = m_pScanner->getNextToken(); if (token != closingBracket) { reportError("XmlParser::parse", __LINE__, "Closing Bracket expected!", getInputFileLineCounter()); } // Go to start state of the state machine continue; } // end of Read "?" // Read "!", i.e. we have a XML comment <!-- bla --> if (token == exclamationMark) { // A preambel comment <!lala > which could be also nested if ((m_pScanner->getNextToken() != minus) || (m_pScanner->getNextToken() != minus)) { if (!m_pScanner->skipUntilMatchingClosingBracket()) { reportError("XmlParser::parse", __LINE__, "Could not find closing comment bracket!", getInputFileLineCounter()); } continue; } // Find end of comment bool endOfCommentFound = false; while (!endOfCommentFound) { // Skip until we find a - (and skip over it) if (!m_pScanner->skipUntil('-', true)) { reportError("XmlParser::parse", __LINE__, "Closing --> of comment not found!", getInputFileLineCounter()); } // The next characters must be -> (note that one minus is already consumed) if ((m_pScanner->getNextToken() == minus) && (m_pScanner->getNextToken() == closingBracket)) { endOfCommentFound = true; } } // while // Go to start state of the state machine continue; } // end of Read "!" // We have found an identifier, i.e. a tag name if (token == identifier) { // Get hash element of token string HashedString *tagName = hashString(m_pScanner->getCurrentTokenString()); // Create new tag object currentTagObject = new XmlTagObject(tagName); if (currentTagObject == 0) { OGDF_THROW(InsufficientMemoryException); } //push (opening) tagName to stack m_tagObserver.push(tagName->key()); // set depth of current tag object currentTagObject->setDepth(m_recursionDepth); // set line of the tag object in the parsed xml document currentTagObject->setLine(getInputFileLineCounter()); // Next token token = m_pScanner->getNextToken(); // Again we found an identifier, so it must be an attribute if (token == identifier) { // Read list of attributes do { // Save the attribute name HashedString *attributeName = hashString(m_pScanner->getCurrentTokenString()); // Consume "=", otherwise failure token = m_pScanner->getNextToken(); if (token != equalSign) { reportError("XmlParser::parse", __LINE__, "Equal Sign expected!", getInputFileLineCounter()); } // Read value token = m_pScanner->getNextToken(); if ((token != quotedValue) && (token != identifier) && (token != attributeValue)) { reportError("XmlParser::parse", __LINE__, "No valid attribute value!", getInputFileLineCounter()); } // Create a new XmlAttributeObject XmlAttributeObject *currentAttributeObject = new XmlAttributeObject(attributeName, hashString(m_pScanner->getCurrentTokenString())); if (currentAttributeObject == 0) { OGDF_THROW(InsufficientMemoryException); } // Append attribute to attribute list of the current tag object appendAttributeObject(currentTagObject, currentAttributeObject); // Get next token token = m_pScanner->getNextToken(); } while (token == identifier); } // Found an identifier of an attribute // Read "/", i.e. the tag is ended immeadiately, e.g. // <A ... /> without a closing tag </A> if (token == slash) { // Consume ">", otherwise failure token = m_pScanner->getNextToken(); if (token != closingBracket) { reportError("XmlParser::parse", __LINE__, "Closing Bracket expected!", getInputFileLineCounter()); } // The tag is closed and ended so we return string s = m_tagObserver.pop(); --m_recursionDepth; return currentTagObject; } // end of Read "/" // Read ">", i.e. the tag is closed and we // expect some content if (token == closingBracket) { // We read something different from "<", so we have to // deal with a tag value now, i.e. a string inbetween the // opening and the closing tag, e.g. <A ...> lalala </A> if (m_pScanner->testNextToken() != openingBracket) { // Read the characters until "<" is reached and put them into // currentTagObject m_pScanner->readStringUntil('<'); currentTagObject->m_pTagValue = hashString(m_pScanner->getCurrentTokenString()); // We expect a closing tag now, i.e. </id> token = m_pScanner->getNextToken(); if (token != openingBracket) { reportError("XmlParser::parse", __LINE__, "Opening Bracket expected!", getInputFileLineCounter()); } token = m_pScanner->getNextToken(); if (token != slash) { reportError("XmlParser::parse", __LINE__, "Slash expected!", getInputFileLineCounter()); } token = m_pScanner->getNextToken(); if (token != identifier) { reportError("XmlParser::parse", __LINE__, "Identifier expected!", getInputFileLineCounter()); } // next token is the closing tag string nextTag(m_pScanner->getCurrentTokenString()); // pop corresponding tag from stack string s = m_tagObserver.pop(); // compare the two tags if (s != nextTag) { // the closing tag doesn't correspond to the opening tag: reportError("XmlParser::parse", __LINE__, "wrong closing tag!", getInputFileLineCounter()); } token = m_pScanner->getNextToken(); if (token != closingBracket) { reportError("XmlParser::parse", __LINE__, "Closing Bracket expected!", getInputFileLineCounter()); } // The tag is closed so we return --m_recursionDepth; return currentTagObject; } // end of read something different from "<" // Found "<", so a (series of) new tag begins and we have to perform // recursive invocation of parse() // // There are two exceptions: // - a slash follows afer <, i.e. we have a closing tag // - an exclamation mark follows after <, i.e. we have a comment while (m_pScanner->testNextToken() == openingBracket) { // Leave the while loop if a closing tag occurs if (m_pScanner->testNextNextToken() == slash) { break; } // Ignore comments if (m_pScanner->testNextNextToken() == exclamationMark) { // Comment must start with <!-- if ((m_pScanner->getNextToken() != openingBracket) || (m_pScanner->getNextToken() != exclamationMark) || (m_pScanner->getNextToken() != minus) || (m_pScanner->getNextToken() != minus)) { reportError("XmlParser::parse", __LINE__, "Comment must start with <!--", getInputFileLineCounter()); } // Find end of comment bool endOfCommentFound = false; while (!endOfCommentFound) { // Skip until we find a - (and skip over it) if (!m_pScanner->skipUntil('-', true)) { reportError("XmlParser::parse", __LINE__, "Closing --> of comment not found!", getInputFileLineCounter()); } // The next characters must be -> (note that one minus is already consumed) if ((m_pScanner->getNextToken() == minus) && (m_pScanner->getNextToken() == closingBracket)) { endOfCommentFound = true; } } // while // Proceed with outer while loop continue; } // Ignore comments // The new tag object is a son of the current tag object XmlTagObject *sonTagObject = parse(); appendSonTagObject(currentTagObject, sonTagObject); } // while // Now we have found all tags. // We expect a closing tag now, i.e. </id> token = m_pScanner->getNextToken(); if (token != openingBracket) { reportError("XmlParser::parse", __LINE__, "Opening Bracket expected!", getInputFileLineCounter()); } token = m_pScanner->getNextToken(); if (token != slash) { reportError("XmlParser::parse", __LINE__, "Slash expected!", getInputFileLineCounter()); } token = m_pScanner->getNextToken(); if (token != identifier) { reportError("XmlParser::parse", __LINE__, "Identifier expected!", getInputFileLineCounter()); } // next token is the closing tag string nextTag(m_pScanner->getCurrentTokenString()); // pop corresponding tag from stack string s = m_tagObserver.pop(); // compare the two tags if (s != nextTag) { // the closing tag doesn't correspond to the opening tag: reportError("XmlParser::parse", __LINE__, "wrong closing tag!", getInputFileLineCounter()); } token = m_pScanner->getNextToken(); if (token != closingBracket) { reportError("XmlParser::parse", __LINE__, "Closing Bracket expected!", getInputFileLineCounter()); } --m_recursionDepth; // check if Document contains code after the last closing bracket if (m_recursionDepth == 0) { token = m_pScanner->getNextToken(); if (token != endOfFile) { reportError("XmlParser::parse", __LINE__, "Document contains code after the last closing bracket!", getInputFileLineCounter()); } } return currentTagObject; } // end of Read ">" OGDF_ASSERT(false) //continue; } // end of found identifier OGDF_ASSERT(false) } // end of while (true)