Browse Source

XmlElement: Add range-for-compatible iterators

tags/2021-05-28
reuk 4 years ago
parent
commit
40f6ac7c47
No known key found for this signature in database GPG Key ID: 9ADCD339CFC98A11
1 changed files with 149 additions and 56 deletions
  1. +149
    -56
      modules/juce_core/xml/juce_XmlElement.h

+ 149
- 56
modules/juce_core/xml/juce_XmlElement.h View File

@@ -23,61 +23,6 @@
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.
@@ -695,6 +640,102 @@ public:
/** Checks if a given string is a valid XML name */
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. */
JUCE_DEPRECATED (String createDocument (StringRef dtdToUse,
@@ -717,8 +758,8 @@ public:
StringRef encodingType = "UTF-8",
int lineWrapLength = 60) const);
//==============================================================================
private:
//==============================================================================
struct XmlAttributeNode
{
XmlAttributeNode (const XmlAttributeNode&) noexcept;
@@ -758,4 +799,56 @@ private:
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

Loading…
Cancel
Save