#include "XML.h" using namespace Framework; using namespace XML; // Erstellt ein XML Element // string: entweder der name des Elements oder ein XML Text der geparsed werden soll Element::Element( Text string ) : Element( string, 0 ) {} // Erstellt ein XML Element // string: entweder der name des Elements oder ein XML Text der geparsed werden soll // zParent: Ein Zeiger auf das eltern element (ohne erhöhten reference Counter) Element::Element( Text string, Element *zParent ) : ReferenceCounter() { children = new RCArray< Element >(); attributes = new RCArray< Text >(); attributeValues = new RCArray< Text >(); text = new Text(); name = new Text(); string.removeWhitespaceAfter( 0 ); string.removeWhitespaceBefore( string.getLength() ); setText( string ); if( string[ 0 ] == '<' && string[ string.getLength() - 1 ] == '>' ) { string.removeWhitespaceAfter( 1 ); string.removeWhitespaceBefore( string.getLength() - 1 ); int nameEnd = 0; for( int i = 1; i < string.getLength(); i++ ) { if( ( string[ i ] < 'a' || string[ i ] > 'z' ) && ( string[ i ] < 'A' || string[ i ] > 'Z' ) && ( string[ i ] < '0' || string[ i ] > '9' ) && string[ i ] != '-' ) { nameEnd = i; break; } } name->setText( string.getTeilText( 1, nameEnd ) ); if( string.hatAt( string.getLength() - 1 - name->getLength(), name->getText() ) || string[ string.getLength() - 2 ] == '/' ) { string.removeWhitespaceAfter( nameEnd ); // parse attributes int start = nameEnd; while( string[ nameEnd ] != '>' && string[ nameEnd ] != '/' ) { for( int i = nameEnd + 1; i < string.getLength(); i++ ) { if( ( string[ i ] < 'a' || string[ i ] > 'z' ) && ( string[ i ] < 'A' || string[ i ] > 'Z' ) && ( string[ i ] < '0' || string[ i ] > '9' ) && string[ i ] != '-' ) { nameEnd = i; break; } } Text *attrName = string.getTeilText( start, nameEnd ); string.removeWhitespaceAfter( nameEnd ); if( string[ nameEnd ] == '=' ) { string.removeWhitespaceAfter( nameEnd + 1 ); Text value = ""; if( string[ nameEnd + 1 ] == '"' ) { bool esc = 0; start = nameEnd + 2; for( int i = nameEnd + 2; string[ i ]; i++ ) { if( string[ i ] == '\\' ) esc = !esc; else { if( string[ i ] == '"' && !esc ) { nameEnd = i + 1; break; } esc = 0; } } value.setText( string.getTeilText( start, nameEnd - 1 ) ); value.ersetzen( "\\\"", "\"" ); } if( string[ nameEnd + 1 ] == '\'' ) { bool esc = 0; start = nameEnd + 2; for( int i = nameEnd + 2; string[ i ]; i++ ) { if( string[ i ] == '\\' ) esc = !esc; else { if( string[ i ] == '\'' && !esc ) { nameEnd = i + 1; break; } esc = 0; } } value.setText( string.getTeilText( start, nameEnd - 1 ) ); value.ersetzen( "\\'", "'" ); } setAttribute( attrName->getText(), value ); } else setAttribute( attrName->getText(), "" ); attrName->release(); string.removeWhitespaceAfter( nameEnd ); start = nameEnd; } if( string[ string.getLength() - 2 ] != '/' ) { string.removeWhitespaceBefore( string.getLength() - 1 - name->getLength() ); if( string[ string.getLength() - 2 - name->getLength() ] == '/' ) { string.removeWhitespaceBefore( string.getLength() - 2 - name->getLength() ); if( string[ string.getLength() - 3 - name->getLength() ] == '<' ) { text->setText( string.getTeilText( nameEnd + 1, string.getLength() - 3 - name->getLength() ) ); // parse children text->removeWhitespaceAfter( 0 ); text->removeWhitespaceBefore( text->getLength() ); if( text->getText()[ 0 ] == '<' && text->getText()[ text->getLength() - 1 ] == '>' ) { int start = 0; int lastStart = -1; while( start < text->getLength() ) { if (lastStart == start) break; lastStart = start; bool esc = 0; bool inString1 = 0; bool inString2 = 0; int poc = 0; bool lastSlash = 0; bool lastOpen = 0; bool openSlash = 0; for( int i = 0; text->getText()[ i ]; i++ ) { switch( text->getText()[ i ] ) { case '\\': esc = !esc; lastSlash = 0; lastOpen = 0; break; case '"': if( !esc && !inString2 ) inString1 = !inString1; esc = 0; lastSlash = 0; lastOpen = 0; break; case '\'': if( !esc && !inString1 ) inString2 = !inString2; esc = 0; lastSlash = 0; lastOpen = 0; break; case '<': if( !inString1 && !inString2 ) lastOpen = 1; esc = 0; lastSlash = 0; break; case '/': lastSlash = 0; if( !inString1 && !inString2 ) { lastSlash = 1; if( lastOpen ) openSlash = 1; } esc = 0; lastOpen = 0; break; case '>': if( !inString1 && !inString2 ) { if( openSlash ) poc--; else if( !lastSlash ) poc++; if( poc == 0 ) { Text *str = text->getTeilText( start, i + 1 ); addChild( new Element( str->getText(), this ) ); str->release(); start = i + 1; } } esc = 0; lastSlash = 0; openSlash = 0; break; default: esc = 0; if( text->getText()[ i ] != ' ' && text->getText()[ i ] != '\t' && text->getText()[ i ] != '\r' && text->getText()[ i ] != '\n' ) { lastSlash = 0; lastOpen = 0; } } } } } } } } else text->setText( "" ); } } parent = zParent; } Element::~Element() { children->release(); attributes->release(); attributeValues->release(); text->release(); name->release(); } // ändert ein attribut oder fügt eines hinzu // attribut: Der Name des Attributes // value: Der Wert des Attributes void Element::setAttribute( Text attribut, Text value ) { for( auto i = attributes->begin(), j = attributeValues->begin(); i && j; i++, j++ ) { if( i->istGleich( attribut ) ) { j->setText( value ); return; } } attributes->add( new Text( attribut ) ); attributeValues->add( new Text( value ) ); } // entfernt ein attribut // attribut: Der Name des Attributes void Element::removeAttribute( Text attribut ) { for( int i = 0; i < attributes->getEintragAnzahl(); i++ ) { if( attributes->z( i )->istGleich( attribut ) ) { attributes->remove( i ); attributeValues->remove( i ); i--; } } } // fügt ein child hinzu // child: Das neue Child Element void Element::addChild( Element *child ) { child->parent = this; children->add( child ); } // fügt ein child hinzu // child: Das neue Child Element void Element::addChildAtFront( Element *child ) { child->parent = this; children->add( child, 0 ); } // entfernt ein child // zChild: das zu entfernende Child void Element::removeChild( Element *child ) { for( int i = 0; i < children->getEintragAnzahl(); i++ ) { if( children->z( i ) == child ) { children->remove( i ); i--; } } child->release(); } // entfernt das i-te child // i: der Index des childs (bei 0 beginnend) void Element::removeChild( int i ) { children->remove( i ); } // entfernt alle childs void Element::removeAllChilds() { children->leeren(); } // entfernt eine Liste mit childs // childs: alle Childs die entfernt werden sollen void Element::removeChilds( RCArray *childs ) { for( auto i : *childs ) removeChild( dynamic_cast( i->getThis() ) ); childs->release(); } // entfernt dieses Element vom Eltern element void Element::remove() { if( parent ) parent->removeChild( dynamic_cast( getThis() ) ); } // setzt den Text in dem Element falls es keine childs gibt // text: dert Text void Element::setText( Text text ) { this->text->setText( text ); } // gibt den Text im Element zurück Text Element::getText() const { return text->getText(); } // gibt die Anzahl der Childs zurück int Element::getChildCount() const { return children->getEintragAnzahl(); } // gibt das i-te child zurück Element *Element::getChild( int i ) const { return children->get( i ); } // gibt das i-te child zurück (ohne erhöhten reference Counter) Element *Element::zChild( int i ) const { return children->z( i ); } // gibt das parent element zurück Element *Element::getParent() const { return parent ? dynamic_cast( parent->getThis() ) : 0; } // gibt das parent element zurück (ohne erhöhten reference Counter) Element *Element::zParent() const { return parent; } // gibt einen iterator zurück mit dem durch alle childs iteriert werden kann Iterator< Element * > Element::getChilds() const { return children->begin(); } // gibt einen selector zurück der alle childs beinhaltet Editor Element::selectChildren() const { return Editor( dynamic_cast *>( children->getThis() ) ); } // gibt eine Liste mit childs zurück, die einen bestimmten Namen haben // name: der name der Childs Editor Element::selectChildsByName( Text name ) const { RCArray< Element > *tmp = new RCArray< Element >(); for( auto i : *children ) { if( i->getName().istGleich( name ) ) tmp->add( dynamic_cast( i->getThis() ) ); } return Editor( tmp ); } // gibt eine Liste mit childs zurück, die ein bestimmtes Attribut haben // attribute: der name des Attributes Editor Element::selectChildsByAttribute( Text attribute ) const { RCArray< Element > *tmp = new RCArray< Element >(); for( auto i : *children ) { if( i->hasAttribute( attribute ) ) tmp->add( dynamic_cast( i->getThis() ) ); } return Editor( tmp ); } // gibt eine Liste mit childs zurück, die ein bestimmtes Attribut mit einem bestimmten wert haben // attribute: der name des Attributes // value: der Wert des Attributes Editor Element::selectChildsByAttribute( Text attribute, Text value ) const { RCArray< Element > *tmp = new RCArray< Element >(); for( auto i : *children ) { if( i->hasAttribute( attribute ) && i->getAttributeValue( attribute ).istGleich( value ) ) tmp->add( dynamic_cast( i->getThis() ) ); } return Editor( tmp ); } // gibt 1 zurück, falls ein Attribut Name existiert, 0 sonnst bool Element::hasAttribute( Text name ) const { for( auto i : *attributes ) { if( i->istGleich( name ) ) return 1; } return 0; } // gibt die Anzahl der Attribute zurück int Element::getAttributeCount() const { return attributes->getEintragAnzahl(); } // gibt den Namen des i-ten Attributes zurück Text Element::getAttributeName( int i ) const { return attributes->z( i )->getText(); } // gibt den Wert des i-ten Attributes zurück Text Element::getAttributeValue( int i ) const { return attributeValues->z( i )->getText(); } // gibt den Wert eines Attributes zurück // attribut: Der Name des Attributes Text Element::getAttributeValue( Text attribut ) const { for( auto i = attributes->begin(), j = attributeValues->begin(); i && j; i++, j++ ) { if( i->istGleich( attribut ) ) return j->getText(); } return ""; } // gibt einen iterator zurück mit dem durch alle Attribut Namen iteriert werden kann Iterator< Text * > Element::getAttributeNames() const { return attributes->begin(); } // gibt einen iterator zurück mit dem durch alle Attribut Werte iteriert werden kann Iterator< Text * > Element::getAttributeValues() const { return attributeValues->begin(); } // gibt den Namen des Elementes zurück zurück Text Element::getName() const { return name->getText(); } // erzeugt einen XML Text der dieses Element und alle childs beinhaltet Text Element::toString() const { Text ret = "<"; ret += name->getText(); if( attributes->getEintragAnzahl() ) ret += " "; for( auto i = attributes->begin(), j = attributeValues->begin(); i && j; i++, j++ ) { ret += i->getText(); if( j->getLength() ) { if( j->hat( '"' ) ) { ret += "='"; Text txt = j->getText(); txt.ersetzen( "'", "\\'" ); ret += txt; ret += "'"; } else { ret += "=\""; Text txt = j->getText(); txt.ersetzen( "\"", "\\\"" ); ret += txt; ret += "\""; } } if( i.hasNext() ) ret += " "; } if( children->getEintragAnzahl() || text->getLength() ) { ret += ">"; if( children->getEintragAnzahl() ) { for( auto i : *children ) ret += i->toString(); } else ret += text->getText(); ret += "getText(); ret += ">"; } else ret += "/>"; return ret; } // Erzeugt eine Kopie ohne referenzen auf dieses objekt Element *Element::dublicate() const { return new Element( toString() ); } // Erzeugt einen neuen XML Editor mit einer Liste von Objekten die editiert werden sollen Editor::Editor( RCArray< Element > *elements ) : ReferenceCounter() { this->elements = new RCArray< Element >(); for( auto i : *elements ) this->elements->add( dynamic_cast( i->getThis() ) ); elements->release(); } Editor::Editor( const Editor &e ) : Editor( dynamic_cast *>( e.elements->getThis() ) ) {} Editor::~Editor() { elements->release(); } // ändert ein attribut oder fügt eines hinzu (auf allen elementen in der Liste) // attribut: Der Name des Attributes // value: Der Wert des Attributes void Editor::setAttribute( Text attribut, Text value ) { for( auto i : *elements ) i->setAttribute( attribut, value ); } // entfernt ein attribut (auf allen elementen in der Liste) // attribut: Der Name des Attributes void Editor::removeAttribute( Text attribut ) { for( auto i : *elements ) i->removeAttribute( attribut ); } // fügt ein child hinzu (auf allen elementen in der Liste) // child: Das neue Child Element void Editor::addChild( Element *child ) { for( auto i : *elements ) i->addChild( child->dublicate() ); child->release(); } // entfernt ein child (auf allen elementen in der Liste) // zChild: das zu entfernende Child void Editor::removeChild( Element *child ) { for( auto i : *elements ) i->removeChild( dynamic_cast( child->getThis() ) ); child->release(); } // entfernt das i-te child (auf allen elementen in der Liste) // i: der Index des childs (bei 0 beginnend) void Editor::removeChild( int i ) { for( auto j : *elements ) j->removeChild( i ); } // entfernt alle childs (auf allen elementen in der Liste) void Editor::removeAllChilds() { for( auto i : *elements ) i->removeAllChilds(); } // entfernt eine Liste mit childs (auf allen elementen in der Liste) // childs: alle Childs die entfernt werden sollen void Editor::removeChilds( RCArray *childs ) { for( auto i : *elements ) i->removeChilds( dynamic_cast *>( childs->getThis() ) ); childs->release(); } // entfernt dieses Element vom Eltern element (auf allen elementen in der Liste) void Editor::remove() { for( auto i : *elements ) i->remove(); } // setzt den Text in dem Element falls es keine childs gibt (auf allen elementen in der Liste) // text: dert Text void Editor::setText( Text text ) { for( auto i : *elements ) i->setText( text ); } // Gibt ein Iterator durch alle Elemente zurück Iterator Editor::getIterator() { return elements->begin(); } // gibt einen selector zurück der alle childs beinhaltet Editor Editor::selectChildren() const { RCArray *list = new RCArray(); for( auto i : *elements ) { for( auto j = i->selectChildren().getIterator(); j; j++ ) { list->add( dynamic_cast( j->getThis() ) ); } } return Editor( list ); } // gibt einen selector zurück der alle parents beinhaltet Editor Editor::selectParents() const { RCArray *list = new RCArray(); for( auto i : *elements ) { if( i->parent ) list->add( dynamic_cast( i->parent->getThis() ) ); } return Editor( list ); } // gibt eine Liste mit elementen zurück, die einen bestimmten Namen haben // name: der name der Childs Editor Editor::whereNameEquals( Text name ) const { RCArray *list = new RCArray(); for( auto i : *elements ) { if( i->getName().istGleich( name ) ) list->add( dynamic_cast( i->getThis() ) ); } return Editor( list ); } // gibt eine Liste mit elementen zurück, die ein bestimmtes child haben // name: der name des childs Editor Editor::whereChildWithNameExists( Text name ) const { RCArray *list = new RCArray(); for( auto i : *elements ) { if( i->selectChildsByName( name ).elements->getEintragAnzahl() ) list->add( dynamic_cast( i->getThis() ) ); } return Editor( list ); } // gibt eine Liste mit elementen zurück, die ein bestimmtes child haben // attribute: der name des attributes Editor Editor::whereChildWithAttributeExists( Text attribute ) const { RCArray *list = new RCArray(); for( auto i : *elements ) { if( i->selectChildsByAttribute( attribute ).elements->getEintragAnzahl() ) list->add( dynamic_cast( i->getThis() ) ); } return Editor( list ); } // gibt eine Liste mit elementen zurück, die ein bestimmtes child haben // attribute: der name des attributes // value: der Wert des Attributes Editor Editor::whereChildWithAttributeExists( Text attribute, Text value ) const { RCArray *list = new RCArray(); for( auto i : *elements ) { if( i->selectChildsByAttribute( attribute, value ).elements->getEintragAnzahl() ) list->add( dynamic_cast( i->getThis() ) ); } return Editor( list ); } // gibt eine Liste mit elementen zurück, die ein bestimmtes Attribut haben // attribute: der name des Attributes Editor Editor::whereAttributeExists( Text attribute ) const { RCArray *list = new RCArray(); for( auto i : *elements ) { if( i->hasAttribute( attribute ) ) list->add( dynamic_cast( i->getThis() ) ); } return Editor( list ); } // gibt eine Liste mit elementen zurück, die ein bestimmtes Attribut mit einem bestimmten wert haben // attribute: der name des Attributes // value: der Wert des Attributes Editor Editor::whereAttributeEquals( Text attribute, Text value ) const { RCArray *list = new RCArray(); for( auto i : *elements ) { if( i->hasAttribute( attribute ) && i->getAttributeValue( attribute ).istGleich( value ) ) list->add( dynamic_cast( i->getThis() ) ); } return Editor( list ); } // Gibt einen Editor zurück welcher nurnoch die Elemente enthält die nicht in e sind // e: Ein Editor mit elementen die nicht enthalten sein sollen Editor Editor::without( Editor e ) const { RCArray *list = new RCArray(); for( auto i : *elements ) { bool found = 0; for( auto j : *e.elements ) found |= i == j; if( !found ) list->add( dynamic_cast( i->getThis() ) ); } return Editor( list ); } // Ruft eine funktion für jedes Element auf // f: die funktion (nimmt als argument ein Element objekt ohne erhöhten reference Counter) void Editor::forEach( std::function< void( Element * ) > f ) const { for( auto i : *elements ) f( i ); }