| @@ -23,61 +23,6 @@ | |||||
| namespace juce | namespace juce | ||||
| { | { | ||||
| //============================================================================== | |||||
| /** A handy macro to make it easy to iterate all the child elements in an XmlElement. | |||||
| The parentXmlElement should be a reference to the parent XML, and the childElementVariableName | |||||
| will be the name of a pointer to each child element. | |||||
| E.g. @code | |||||
| XmlElement* myParentXml = createSomeKindOfXmlDocument(); | |||||
| forEachXmlChildElement (*myParentXml, child) | |||||
| { | |||||
| if (child->hasTagName ("FOO")) | |||||
| doSomethingWithXmlElement (child); | |||||
| } | |||||
| @endcode | |||||
| @see forEachXmlChildElementWithTagName | |||||
| */ | |||||
| #define forEachXmlChildElement(parentXmlElement, childElementVariableName) \ | |||||
| \ | |||||
| for (auto* childElementVariableName = (parentXmlElement).getFirstChildElement(); \ | |||||
| childElementVariableName != nullptr; \ | |||||
| childElementVariableName = childElementVariableName->getNextElement()) | |||||
| /** A macro that makes it easy to iterate all the child elements of an XmlElement | |||||
| which have a specified tag. | |||||
| This does the same job as the forEachXmlChildElement macro, but only for those | |||||
| elements that have a particular tag name. | |||||
| The parentXmlElement should be a reference to the parent XML, and the childElementVariableName | |||||
| will be the name of a pointer to each child element. The requiredTagName is the | |||||
| tag name to match. | |||||
| E.g. @code | |||||
| XmlElement* myParentXml = createSomeKindOfXmlDocument(); | |||||
| forEachXmlChildElementWithTagName (*myParentXml, child, "MYTAG") | |||||
| { | |||||
| // the child object is now guaranteed to be a <MYTAG> element.. | |||||
| doSomethingWithMYTAGElement (child); | |||||
| } | |||||
| @endcode | |||||
| @see forEachXmlChildElement | |||||
| */ | |||||
| #define forEachXmlChildElementWithTagName(parentXmlElement, childElementVariableName, requiredTagName) \ | |||||
| \ | |||||
| for (auto* childElementVariableName = (parentXmlElement).getChildByName (requiredTagName); \ | |||||
| childElementVariableName != nullptr; \ | |||||
| childElementVariableName = childElementVariableName->getNextElementWithTagName (requiredTagName)) | |||||
| //============================================================================== | //============================================================================== | ||||
| /** Used to build a tree of elements representing an XML document. | /** Used to build a tree of elements representing an XML document. | ||||
| @@ -695,6 +640,102 @@ public: | |||||
| /** Checks if a given string is a valid XML name */ | /** Checks if a given string is a valid XML name */ | ||||
| static bool isValidXmlName (StringRef possibleName) noexcept; | static bool isValidXmlName (StringRef possibleName) noexcept; | ||||
| private: | |||||
| //============================================================================== | |||||
| struct GetNextElement | |||||
| { | |||||
| XmlElement* getNext (const XmlElement& e) const { return e.getNextElement(); } | |||||
| }; | |||||
| struct GetNextElementWithTagName | |||||
| { | |||||
| GetNextElementWithTagName() = default; | |||||
| explicit GetNextElementWithTagName (String n) : name (std::move (n)) {} | |||||
| XmlElement* getNext (const XmlElement& e) const { return e.getNextElementWithTagName (name); } | |||||
| String name; | |||||
| }; | |||||
| //============================================================================== | |||||
| template <typename Traits> | |||||
| class Iterator : private Traits | |||||
| { | |||||
| public: | |||||
| using difference_type = ptrdiff_t; | |||||
| using value_type = XmlElement*; | |||||
| using pointer = const value_type*; | |||||
| using reference = value_type; | |||||
| using iterator_category = std::input_iterator_tag; | |||||
| Iterator() = default; | |||||
| template <typename... Args> | |||||
| Iterator (XmlElement* e, Args&&... args) | |||||
| : Traits (std::forward<Args> (args)...), element (e) {} | |||||
| Iterator begin() const { return *this; } | |||||
| Iterator end() const { return Iterator{}; } | |||||
| bool operator== (const Iterator& other) const { return element == other.element; } | |||||
| bool operator!= (const Iterator& other) const { return ! operator== (other); } | |||||
| reference operator*() const { return element; } | |||||
| pointer operator->() const { return &element; } | |||||
| Iterator& operator++() | |||||
| { | |||||
| element = Traits::getNext (*element); | |||||
| return *this; | |||||
| } | |||||
| Iterator operator++(int) | |||||
| { | |||||
| auto copy = *this; | |||||
| ++(*this); | |||||
| return copy; | |||||
| } | |||||
| private: | |||||
| value_type element = nullptr; | |||||
| }; | |||||
| public: | |||||
| //============================================================================== | |||||
| /** Allows iterating the children of an XmlElement using range-for syntax. | |||||
| @code | |||||
| void doSomethingWithXmlChildren (const XmlElement& myParentXml) | |||||
| { | |||||
| for (auto* element : myParentXml.getChildIterator()) | |||||
| doSomethingWithXmlElement (element); | |||||
| } | |||||
| @endcode | |||||
| */ | |||||
| Iterator<GetNextElement> getChildIterator() const | |||||
| { | |||||
| return Iterator<GetNextElement> { getFirstChildElement() }; | |||||
| } | |||||
| /** Allows iterating children of an XmlElement with a specific tag using range-for syntax. | |||||
| @code | |||||
| void doSomethingWithXmlChildren (const XmlElement& myParentXml) | |||||
| { | |||||
| for (auto* element : myParentXml.getChildWithTagNameIterator ("MYTAG")) | |||||
| doSomethingWithXmlElement (element); | |||||
| } | |||||
| @endcode | |||||
| */ | |||||
| Iterator<GetNextElementWithTagName> getChildWithTagNameIterator (const String& name) const | |||||
| { | |||||
| return Iterator<GetNextElementWithTagName> { getChildByName (name), name }; | |||||
| } | |||||
| /** This allows us to trigger a warning inside deprecated macros. */ | |||||
| #ifndef DOXYGEN | |||||
| JUCE_DEPRECATED_WITH_BODY (void macroBasedForLoop() const noexcept, {}) | |||||
| #endif | |||||
| //============================================================================== | //============================================================================== | ||||
| /** This has been deprecated in favour of the toString() method. */ | /** This has been deprecated in favour of the toString() method. */ | ||||
| JUCE_DEPRECATED (String createDocument (StringRef dtdToUse, | JUCE_DEPRECATED (String createDocument (StringRef dtdToUse, | ||||
| @@ -717,8 +758,8 @@ public: | |||||
| StringRef encodingType = "UTF-8", | StringRef encodingType = "UTF-8", | ||||
| int lineWrapLength = 60) const); | int lineWrapLength = 60) const); | ||||
| //============================================================================== | |||||
| private: | private: | ||||
| //============================================================================== | |||||
| struct XmlAttributeNode | struct XmlAttributeNode | ||||
| { | { | ||||
| XmlAttributeNode (const XmlAttributeNode&) noexcept; | XmlAttributeNode (const XmlAttributeNode&) noexcept; | ||||
| @@ -758,4 +799,56 @@ private: | |||||
| JUCE_LEAK_DETECTOR (XmlElement) | JUCE_LEAK_DETECTOR (XmlElement) | ||||
| }; | }; | ||||
| //============================================================================== | |||||
| /** DEPRECATED: A handy macro to make it easy to iterate all the child elements in an XmlElement. | |||||
| New code should avoid this macro, and instead use getChildIterator directly. | |||||
| The parentXmlElement should be a reference to the parent XML, and the childElementVariableName | |||||
| will be the name of a pointer to each child element. | |||||
| E.g. @code | |||||
| XmlElement* myParentXml = createSomeKindOfXmlDocument(); | |||||
| forEachXmlChildElement (*myParentXml, child) | |||||
| { | |||||
| if (child->hasTagName ("FOO")) | |||||
| doSomethingWithXmlElement (child); | |||||
| } | |||||
| @endcode | |||||
| @see forEachXmlChildElementWithTagName | |||||
| */ | |||||
| #define forEachXmlChildElement(parentXmlElement, childElementVariableName) \ | |||||
| for (auto* (childElementVariableName) : ((parentXmlElement).macroBasedForLoop(), (parentXmlElement).getChildIterator())) | |||||
| /** DEPRECATED: A macro that makes it easy to iterate all the child elements of an XmlElement | |||||
| which have a specified tag. | |||||
| New code should avoid this macro, and instead use getChildWithTagNameIterator directly. | |||||
| This does the same job as the forEachXmlChildElement macro, but only for those | |||||
| elements that have a particular tag name. | |||||
| The parentXmlElement should be a reference to the parent XML, and the childElementVariableName | |||||
| will be the name of a pointer to each child element. The requiredTagName is the | |||||
| tag name to match. | |||||
| E.g. @code | |||||
| XmlElement* myParentXml = createSomeKindOfXmlDocument(); | |||||
| forEachXmlChildElementWithTagName (*myParentXml, child, "MYTAG") | |||||
| { | |||||
| // the child object is now guaranteed to be a <MYTAG> element.. | |||||
| doSomethingWithMYTAGElement (child); | |||||
| } | |||||
| @endcode | |||||
| @see forEachXmlChildElement | |||||
| */ | |||||
| #define forEachXmlChildElementWithTagName(parentXmlElement, childElementVariableName, requiredTagName) \ | |||||
| for (auto* (childElementVariableName) : ((parentXmlElement).macroBasedForLoop(), (parentXmlElement).getChildWithTagNameIterator ((requiredTagName)))) | |||||
| } // namespace juce | } // namespace juce | ||||