#include "XML.h" using namespace Framework; using namespace XML; Framework::XML::Element::Element() : ReferenceCounter(), children(new RCArray()), attributes(new RCArray()), attributeValues(new RCArray()), name(new Text()), text(new Text()), parent(0) {} // Creates an XML Element // string: either the name of the element or an XML text to be parsed Element::Element(Text string) : Element(string, 0) {} // Creates an XML Element // string: either the name of the element or an XML text to be parsed // zParent: A pointer to the parent element (without increased reference // counter) Element::Element(Text string, Element* zParent) : Element() { 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; } } Text* tmp = string.getTeilText(1, nameEnd); name->setText(*tmp); tmp->release(); 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; } } tmp = string.getTeilText(start, nameEnd - 1); value.setText(*tmp); tmp->release(); 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; } } tmp = string.getTeilText(start, nameEnd - 1); value.setText(*tmp); tmp->release(); 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()] == '<') { tmp = string.getTeilText(nameEnd + 1, string.getLength() - 3 - name->getLength()); text->setText(*tmp); tmp->release(); // 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(); } // Changes an attribute or adds a new one // attribut: The name of the attribute // value: The value of the attribute 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)); } // Removes an attribute // attribut: The name of the attribute void Element::removeAttribute(Text attribut) { for (int i = 0; i < attributes->getEntryCount(); i++) { if (attributes->z(i)->istGleich(attribut)) { attributes->remove(i); attributeValues->remove(i); i--; } } } // Adds a child // child: The new child element void Element::addChild(Element* child) { child->parent = this; children->add(child); } // Adds a child at the front // child: The new child element void Element::addChildAtFront(Element* child) { child->parent = this; children->add(child, 0); } // Removes a child // zChild: The child to remove void Element::removeChild(Element* child) { for (int i = 0; i < children->getEntryCount(); i++) { if (children->z(i) == child) { children->remove(i); i--; } } child->release(); } // Removes the i-th child // i: The index of the child (starting at 0) void Element::removeChild(int i) { children->remove(i); } // Removes all children void Element::removeAllChilds() { children->leeren(); } // Removes a list of children // childs: All children to be removed void Element::removeChilds(RCArray* childs) { for (auto i : *childs) removeChild(dynamic_cast(i->getThis())); childs->release(); } // Removes this element from the parent element void Element::remove() { if (parent) parent->removeChild(dynamic_cast(getThis())); } // Sets the text in the element if it has no children // text: The text void Element::setText(Text text) { this->text->setText(text); } // Returns the text in the element Text Element::getText() const { return text->getText(); } // Returns the number of children int Element::getChildCount() const { return children->getEntryCount(); } int Framework::XML::Element::getChildIndex(Element* zChild) const { return children->indexOf(zChild); } // Returns the i-th child Element* Element::getChild(int i) const { return children->get(i); } // Returns the i-th child (without increased reference counter) Element* Element::zChild(int i) const { return children->z(i); } // Returns the parent element Element* Element::getParent() const { return parent ? dynamic_cast(parent->getThis()) : 0; } // Returns the parent element (without increased reference counter) Element* Element::zParent() const { return parent; } // Returns an iterator to iterate through all children ArrayIterator Element::getChilds() const { return children->begin(); } //! Returns an editor for this element Editor Element::select() { RCArray* tmp = new RCArray(); tmp->add(dynamic_cast(getThis())); return Editor(tmp); } // Returns a selector containing all children Editor Element::selectChildren() const { return Editor(dynamic_cast*>(children->getThis())); } // Returns a list of children that have a specific name // name: The name of the children 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); } // Returns a list of children that have a specific attribute // attribute: The name of the attribute 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); } // Returns a list of children that have a specific attribute with a // specific value // attribute: The name of the attribute // value: The value of the attribute 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); } // Returns 1 if an attribute name exists, 0 otherwise bool Element::hasAttribute(Text name) const { for (auto i : *attributes) { if (i->istGleich(name)) return 1; } return 0; } // Returns the number of attributes int Element::getAttributeCount() const { return attributes->getEntryCount(); } // Returns the name of the i-th attribute Text Element::getAttributeName(int i) const { return attributes->z(i)->getText(); } // Returns the value of the i-th attribute Text Element::getAttributeValue(int i) const { return attributeValues->z(i)->getText(); } // Returns the value of an attribute // attribut: The name of the attribute const Text& Element::getAttributeValue(const Text& attribut) const { for (auto i = attributes->begin(), j = attributeValues->begin(); i && j; i++, j++) { if (i->istGleich(attribut)) return *j.val(); } return Text::EMPTY; } // Returns an iterator to iterate through all attribute names ArrayIterator Element::getAttributeNames() const { return attributes->begin(); } // Returns an iterator to iterate through all attribute values ArrayIterator Element::getAttributeValues() const { return attributeValues->begin(); } void Framework::XML::Element::setName(Text name) { this->name->setText(name); } // Returns the name of the element Text Element::getName() const { return name->getText(); } // Generates an XML text containing this element and all children Text Element::toString() const { Text ret = "<"; ret += name->getText(); if (attributes->getEntryCount()) 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->getEntryCount() || text->getLength()) { ret += ">"; if (children->getEntryCount()) { for (auto i : *children) ret += i->toString(); } else ret += text->getText(); ret += "getText(); ret += ">"; } else ret += "/>"; return ret; } // Creates a copy without references to this object Element* Element::dublicate() const { return new Element(toString()); } // Creates a new XML Editor with a list of objects to be edited Editor::Editor(RCArray* elements) : ReferenceCounter() { this->elements = elements; } Editor::Editor(const Editor& e) : Editor(dynamic_cast*>(e.elements->getThis())) {} Editor::~Editor() { elements->release(); } Maybe> Framework::XML::Editor::getFirstElement() const { if (this->elements->getEntryCount() > 0) { return Maybe>::of( RCPointer::of(this->elements->get(0))); } return Maybe>::empty(); } // Changes an attribute or adds a new one (on all elements in the list) // attribut: The name of the attribute // value: The value of the attribute void Editor::setAttribute(Text attribut, Text value) { for (auto i : *elements) i->setAttribute(attribut, value); } // Removes an attribute (on all elements in the list) // attribut: The name of the attribute void Editor::removeAttribute(Text attribut) { for (auto i : *elements) i->removeAttribute(attribut); } // Adds a child (on all elements in the list) // child: The new child element void Editor::addChild(Element* child) { for (auto i : *elements) i->addChild(child->dublicate()); child->release(); } // Removes a child (on all elements in the list) // zChild: The child to remove void Editor::removeChild(Element* child) { for (auto i : *elements) i->removeChild(dynamic_cast(child->getThis())); child->release(); } // Removes the i-th child (on all elements in the list) // i: The index of the child (starting at 0) void Editor::removeChild(int i) { for (auto j : *elements) j->removeChild(i); } // Removes all children (on all elements in the list) void Editor::removeAllChilds() { for (auto i : *elements) i->removeAllChilds(); } // Removes a list of children (on all elements in the list) // childs: All children to be removed void Editor::removeChilds(RCArray* childs) { for (auto i : *elements) i->removeChilds( dynamic_cast*>(childs->getThis())); childs->release(); } // Removes this element from the parent element (on all elements in the list) void Editor::remove() { for (auto i : *elements) i->remove(); } // Sets the text in the element if it has no children (on all elements // in the list) // text: The text void Editor::setText(Text text) { for (auto i : *elements) i->setText(text); } // Returns an iterator through all elements ArrayIterator Editor::begin() { return elements->begin(); } //! Returns the end of the iterator ArrayIterator Editor::end() { return elements->end(); } void Editor::selectAllElements(RCArray* zResult) { for (auto i : *elements) { zResult->add(dynamic_cast(i->getThis())); i->selectChildren().selectAllElements(zResult); } } //! returns a selector that contains all elements in the selector and all //! children of these elements recursively Editor Editor::selectAllElements() { RCArray* list = new RCArray(); selectAllElements(list); return Editor(list); } // returns a selector that contains all children 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); } // returns a selector that contains all parents 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); } // returns a list of elements that have a specific name // name: the name of the children 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); } // returns a list of elements that have a specific child // name: the name of the child Editor Editor::whereChildWithNameExists(Text name) const { RCArray* list = new RCArray(); for (auto i : *elements) { if (i->selectChildsByName(name).elements->getEntryCount()) list->add(dynamic_cast(i->getThis())); } return Editor(list); } // returns a list of elements that have a specific child // attribute: the name of the attribute Editor Editor::whereChildWithAttributeExists(Text attribute) const { RCArray* list = new RCArray(); for (auto i : *elements) { if (i->selectChildsByAttribute(attribute).elements->getEntryCount()) list->add(dynamic_cast(i->getThis())); } return Editor(list); } // returns a list of elements that have a specific child // attribute: the name of the attribute // value: the value of the attribute Editor Editor::whereChildWithAttributeExists(Text attribute, Text value) const { RCArray* list = new RCArray(); for (auto i : *elements) { if (i->selectChildsByAttribute(attribute, value) .elements->getEntryCount()) list->add(dynamic_cast(i->getThis())); } return Editor(list); } // returns a list of elements that have a specific attribute // attribute: the name of the attribute 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); } // returns a list of elements that have a specific attribute with a // specific value // attribute: the name of the attribute // value: the value of the attribute 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); } // Returns an editor that only contains the elements that are not in e // e: An editor with elements that should not be included 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); } // calls a function for each element // f: the function (takes an Element object without increased reference // counter) void Editor::forEach(std::function f) const { for (auto i : *elements) f(i); } //! returns 1 if the editor contains at least one element, 0 otherwise bool Editor::exists() const { return elements->getEntryCount() > 0; } //! returns the number of elements in the editor int Editor::getSize() const { return elements->getEntryCount(); } 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; }