/* DOM implementation */ #include #include #include #include using namespace std; /* This IS NOT meant to implement the DOM in its normal way. Instead, it's meant to use a universal Node class with getter and setter functions. */ class Node { public: explicit Node( const string& n ) : nodeName( n ) {} Node( const string& n, const string& v ) : nodeName( n ), nodeValue( v ) {} bool hasAttribute( const string& name ) const { return ( attributes.find( name ) != attributes.end() ); } void setAttribute( const string& name, const string& value ) { attributes[ name ] = value; } string getAttribute( const string& name ) const { const map::const_iterator found( attributes.find( name ) ); if ( found != attributes.end() ) { return found->second; } return ""; } void setTextContent( const string& text ) { childNodes.clear(); childNodes.push_back( Node( "#text", text ) ); } string getTextContent() const { if ( nodeName == "#text" ) { return nodeValue; } string temp; if ( hasChildNodes() ) { for ( vector::const_iterator i = childNodes.begin(); i != childNodes.end(); ++i ) { temp += i->getTextContent(); } } return temp; } bool hasChildNodes() const { return !childNodes.empty(); } void appendChild( const Node& e ) { childNodes.push_back( e ); } string getNodeName() const { return nodeName; } void setNodeValue( const string& value ) { if ( nodeName == "#text" ) { nodeValue = value; } } string getNodeValue() const { return nodeValue; } /* returns a vector of pointers that are only valid until you change something. They are NOT 'LIVE' */ vector getNodesByNodeName( const string& name ) { vector matches; for ( vector::size_type i = 0; i < childNodes.size(); ++i ) { if ( childNodes[i].nodeName == name || name == "*" ) { matches.push_back( &childNodes[i] ); } vector sub_matches = childNodes[i].getNodesByNodeName( name ); for ( vector::size_type z = 0; z < sub_matches.size(); ++z ) { matches.push_back( sub_matches[z] ); } } return matches; } string getOuterHTML() const { if ( nodeName == "#text" ) { return nodeValue; } if ( nodeName == "#document" ) { return ""; } string temp; temp += "<"; temp += nodeName; for ( map::const_iterator i = attributes.begin(); i != attributes.end(); ++i ) { temp += " "; temp += i->first; temp += "=\""; temp += i->second; temp += "\""; } if ( !hasChildNodes() ) { temp += "/"; } temp += ">"; if ( hasChildNodes() ) { for ( vector::const_iterator i = childNodes.begin(); i != childNodes.end(); ++i ) { if ( i->nodeName != "#text" ) { temp += i->getOuterHTML(); } else { temp += i->nodeValue; } } temp += ""; } return temp; } string getInnerHTML() const { if ( hasChildNodes() ) { string temp; for ( vector::const_iterator i = childNodes.begin(); i != childNodes.end(); ++i ) { temp += i->getOuterHTML(); } return temp; } return ""; } private: string nodeName; string nodeValue; vector childNodes; map attributes; }; int main() { Node html("html"); html.setAttribute( "lang", "en" ); html.appendChild( Node("head") ); html.appendChild( Node("body") ); Node title("title"); title.appendChild( Node( "#text", "c++ dom" ) ); html.getNodesByNodeName("head")[0]->appendChild( title ); Node p("p"); p.setAttribute( "id", "blabla" ); p.appendChild( Node( "#text", "This is a paragraph" ) ); html.getNodesByNodeName( "body" )[0]->appendChild( p ); cout << html.getTextContent() << endl; cout << html.getOuterHTML() << "\n" << endl; cout << html.getInnerHTML() << "\n" << endl; vector all = html.getNodesByNodeName( "*" ); for ( vector::size_type i = 0; i < all.size(); ++i ) { cout << all[i]->getNodeName() << endl; } html.setTextContent( "bla bla bla" ); cout << html.getInnerHTML() << endl; } // g++ -Wall -Wextra this.cpp -o this -O3 -s