#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(); attributes = new RCArray(); attributeValues = new RCArray(); 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] != '-' && string[i] != '_' && 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] != '-' && string[i] != '_' && 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(); } int Framework::XML::Element::getChildIndex(Element* zChild) const { return children->indexOf(zChild); } // 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 ArrayIterator Element::getChilds() const { return children->begin(); } //! gibt einen Editor für dieses Element zurück Editor Element::select() { RCArray* tmp = new RCArray(); tmp->add(dynamic_cast(getThis())); return Editor(tmp); } // 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* tmp = new RCArray(); 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* tmp = new RCArray(); 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* tmp = new RCArray(); 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 ArrayIterator Element::getAttributeNames() const { return attributes->begin(); } // gibt einen iterator zurück mit dem durch alle Attribut Werte iteriert werden // kann ArrayIterator 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->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* elements) : ReferenceCounter() { this->elements = new RCArray(); 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(); } Maybe> Framework::XML::Editor::getFirstElement() const { if (this->elements->getEintragAnzahl() > 0) { return Maybe>::of( RCPointer::of(this->elements->get(0))); } return Maybe>::empty(); } // ä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 ArrayIterator Editor::begin() { return elements->begin(); } //! Gibt das ende des iterators zurück ArrayIterator Editor::end() { return elements->end(); } //! Gibt einen selector zurück der alle elemente beinhaltet die in diesem //! selector vorkommen und rekursiv alle Kinder der elemente Enthält Editor Editor::selectAllElements() { RCArray* list = new RCArray(); for (auto i : *elements) { list->add(dynamic_cast(i->getThis())); for (Element* j : i->selectChildren().selectAllElements()) { list->add(dynamic_cast(j->getThis())); } } return Editor(list); } // gibt einen selector zurück der alle childs beinhaltet Editor Editor::selectChildren() const { RCArray* list = new RCArray(); for (auto i : *elements) { for (Element* j : i->selectChildren()) { 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 f) const { for (auto i : *elements) f(i); } //! gibt 1 zurück, wenn mindestens ein Element gefunden wurde bool Editor::exists() const { return elements->getEintragAnzahl() > 0; } //! gibt die anzahl der ausgewählten elemente zurück int Editor::getSize() const { return elements->getEintragAnzahl(); } DLLEXPORT Editor& Framework::XML::Editor::operator=(const Editor& e) { if (this != &e) { this->elements->leeren(); for (auto i : *e.elements) this->elements->add(dynamic_cast(i->getThis())); } return *this; }