OpenShot Library | libopenshot-audio 0.2.0
juce_XmlElement.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2017 - ROLI Ltd.
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26inline static bool isValidXmlNameStartCharacter (juce_wchar character) noexcept
27{
28 return character == ':'
29 || character == '_'
30 || (character >= 'a' && character <= 'z')
31 || (character >= 'A' && character <= 'Z')
32 || (character >= 0xc0 && character <= 0xd6)
33 || (character >= 0xd8 && character <= 0xf6)
34 || (character >= 0xf8 && character <= 0x2ff)
35 || (character >= 0x370 && character <= 0x37d)
36 || (character >= 0x37f && character <= 0x1fff)
37 || (character >= 0x200c && character <= 0x200d)
38 || (character >= 0x2070 && character <= 0x218f)
39 || (character >= 0x2c00 && character <= 0x2fef)
40 || (character >= 0x3001 && character <= 0xd7ff)
41 || (character >= 0xf900 && character <= 0xfdcf)
42 || (character >= 0xfdf0 && character <= 0xfffd)
43 || (character >= 0x10000 && character <= 0xeffff);
44}
45
46inline static bool isValidXmlNameBodyCharacter (juce_wchar character) noexcept
47{
48 return isValidXmlNameStartCharacter (character)
49 || character == '-'
50 || character == '.'
51 || character == 0xb7
52 || (character >= '0' && character <= '9')
53 || (character >= 0x300 && character <= 0x036f)
54 || (character >= 0x203f && character <= 0x2040);
55}
56
57XmlElement::XmlAttributeNode::XmlAttributeNode (const XmlAttributeNode& other) noexcept
58 : name (other.name),
59 value (other.value)
60{
61}
62
63XmlElement::XmlAttributeNode::XmlAttributeNode (const Identifier& n, const String& v) noexcept
64 : name (n), value (v)
65{
66 jassert (isValidXmlName (name));
67}
68
69XmlElement::XmlAttributeNode::XmlAttributeNode (String::CharPointerType nameStart, String::CharPointerType nameEnd)
70 : name (nameStart, nameEnd)
71{
72 jassert (isValidXmlName (name));
73}
74
75//==============================================================================
76XmlElement::XmlElement (const String& tag)
77 : tagName (StringPool::getGlobalPool().getPooledString (tag))
78{
79 jassert (isValidXmlName (tagName));
80}
81
83 : tagName (StringPool::getGlobalPool().getPooledString (tag))
84{
85 jassert (isValidXmlName (tagName));
86}
87
89 : tagName (StringPool::getGlobalPool().getPooledString (tag))
90{
91 jassert (isValidXmlName (tagName));
92}
93
95 : tagName (tag.toString())
96{
97 jassert (isValidXmlName (tagName));
98}
99
101 : tagName (StringPool::getGlobalPool().getPooledString (tagNameStart, tagNameEnd))
102{
103 jassert (isValidXmlName (tagName));
104}
105
106XmlElement::XmlElement (int /*dummy*/) noexcept
107{
108}
109
111 : tagName (other.tagName)
112{
113 copyChildrenAndAttributesFrom (other);
114}
115
117{
118 if (this != &other)
119 {
122 tagName = other.tagName;
123 copyChildrenAndAttributesFrom (other);
124 }
125
126 return *this;
127}
128
130 : nextListItem (std::move (other.nextListItem)),
131 firstChildElement (std::move (other.firstChildElement)),
132 attributes (std::move (other.attributes)),
133 tagName (std::move (other.tagName))
134{
135}
136
138{
139 jassert (this != &other); // hopefully the compiler should make this situation impossible!
140
141 removeAllAttributes();
142 deleteAllChildElements();
143
144 nextListItem = std::move (other.nextListItem);
145 firstChildElement = std::move (other.firstChildElement);
146 attributes = std::move (other.attributes);
147 tagName = std::move (other.tagName);
148
149 return *this;
150}
151
152void XmlElement::copyChildrenAndAttributesFrom (const XmlElement& other)
153{
154 jassert (firstChildElement.get() == nullptr);
155 firstChildElement.addCopyOfList (other.firstChildElement);
156
157 jassert (attributes.get() == nullptr);
158 attributes.addCopyOfList (other.attributes);
159}
160
162{
163 firstChildElement.deleteAll();
164 attributes.deleteAll();
165}
166
167//==============================================================================
168namespace XmlOutputFunctions
169{
170 #if 0 // (These functions are just used to generate the lookup table used below)
171 bool isLegalXmlCharSlow (const juce_wchar character) noexcept
172 {
173 if ((character >= 'a' && character <= 'z')
174 || (character >= 'A' && character <= 'Z')
175 || (character >= '0' && character <= '9'))
176 return true;
177
178 const char* t = " .,;:-()_+=?!'#@[]/\\*%~{}$|";
179
180 do
181 {
182 if (((juce_wchar) (uint8) *t) == character)
183 return true;
184 }
185 while (*++t != 0);
186
187 return false;
188 }
189
190 void generateLegalCharLookupTable()
191 {
192 uint8 n[32] = { 0 };
193 for (int i = 0; i < 256; ++i)
194 if (isLegalXmlCharSlow (i))
195 n[i >> 3] |= (1 << (i & 7));
196
197 String s;
198 for (int i = 0; i < 32; ++i)
199 s << (int) n[i] << ", ";
200
201 DBG (s);
202 }
203 #endif
204
205 static bool isLegalXmlChar (const uint32 c) noexcept
206 {
207 static const unsigned char legalChars[] = { 0, 0, 0, 0, 187, 255, 255, 175, 255,
208 255, 255, 191, 254, 255, 255, 127 };
209 return c < sizeof (legalChars) * 8
210 && (legalChars [c >> 3] & (1 << (c & 7))) != 0;
211 }
212
213 static void escapeIllegalXmlChars (OutputStream& outputStream, const String& text, const bool changeNewLines)
214 {
215 auto t = text.getCharPointer();
216
217 for (;;)
218 {
219 auto character = (uint32) t.getAndAdvance();
220
221 if (character == 0)
222 break;
223
224 if (isLegalXmlChar (character))
225 {
226 outputStream << (char) character;
227 }
228 else
229 {
230 switch (character)
231 {
232 case '&': outputStream << "&amp;"; break;
233 case '"': outputStream << "&quot;"; break;
234 case '>': outputStream << "&gt;"; break;
235 case '<': outputStream << "&lt;"; break;
236
237 case '\n':
238 case '\r':
239 if (! changeNewLines)
240 {
241 outputStream << (char) character;
242 break;
243 }
244 // Note: Deliberate fall-through here!
245 default:
246 outputStream << "&#" << ((int) character) << ';';
247 break;
248 }
249 }
250 }
251 }
252
253 static void writeSpaces (OutputStream& out, const size_t numSpaces)
254 {
255 out.writeRepeatedByte (' ', numSpaces);
256 }
257}
258
259void XmlElement::writeElementAsText (OutputStream& outputStream,
260 const int indentationLevel,
261 const int lineWrapLength) const
262{
263 using namespace XmlOutputFunctions;
264
265 if (indentationLevel >= 0)
266 writeSpaces (outputStream, (size_t) indentationLevel);
267
268 if (! isTextElement())
269 {
270 outputStream.writeByte ('<');
271 outputStream << tagName;
272
273 {
274 auto attIndent = (size_t) (indentationLevel + tagName.length() + 1);
275 int lineLen = 0;
276
277 for (auto* att = attributes.get(); att != nullptr; att = att->nextListItem)
278 {
279 if (lineLen > lineWrapLength && indentationLevel >= 0)
280 {
281 outputStream << newLine;
282 writeSpaces (outputStream, attIndent);
283 lineLen = 0;
284 }
285
286 auto startPos = outputStream.getPosition();
287 outputStream.writeByte (' ');
288 outputStream << att->name;
289 outputStream.write ("=\"", 2);
290 escapeIllegalXmlChars (outputStream, att->value, true);
291 outputStream.writeByte ('"');
292 lineLen += (int) (outputStream.getPosition() - startPos);
293 }
294 }
295
296 if (auto* child = firstChildElement.get())
297 {
298 outputStream.writeByte ('>');
299 bool lastWasTextNode = false;
300
301 for (; child != nullptr; child = child->nextListItem)
302 {
303 if (child->isTextElement())
304 {
305 escapeIllegalXmlChars (outputStream, child->getText(), false);
306 lastWasTextNode = true;
307 }
308 else
309 {
310 if (indentationLevel >= 0 && ! lastWasTextNode)
311 outputStream << newLine;
312
313 child->writeElementAsText (outputStream,
314 lastWasTextNode ? 0 : (indentationLevel + (indentationLevel >= 0 ? 2 : 0)), lineWrapLength);
315 lastWasTextNode = false;
316 }
317 }
318
319 if (indentationLevel >= 0 && ! lastWasTextNode)
320 {
321 outputStream << newLine;
322 writeSpaces (outputStream, (size_t) indentationLevel);
323 }
324
325 outputStream.write ("</", 2);
326 outputStream << tagName;
327 outputStream.writeByte ('>');
328 }
329 else
330 {
331 outputStream.write ("/>", 2);
332 }
333 }
334 else
335 {
336 escapeIllegalXmlChars (outputStream, getText(), false);
337 }
338}
339
351
355{
356 using namespace XmlOutputFunctions;
357
359 {
360 output << "<?xml version=\"1.0\" encoding=\"" << encodingType << "\"?>";
361
362 if (allOnOneLine)
363 output.writeByte (' ');
364 else
365 output << newLine << newLine;
366 }
367
368 if (dtdToUse.isNotEmpty())
369 {
370 output << dtdToUse;
371
372 if (allOnOneLine)
373 output.writeByte (' ');
374 else
375 output << newLine;
376 }
377
378 writeElementAsText (output, allOnOneLine ? -1 : 0, lineWrapLength);
379
380 if (! allOnOneLine)
381 output << newLine;
382}
383
386{
387 TemporaryFile tempFile (file);
388
389 {
390 FileOutputStream out (tempFile.getFile());
391
392 if (! out.openedOk())
393 return false;
394
396 out.flush(); // (called explicitly to force an fsync on posix)
397
398 if (out.getStatus().failed())
399 return false;
400 }
401
402 return tempFile.overwriteTargetFileWithTemporary();
403}
404
405//==============================================================================
407{
408 const bool matches = tagName.equalsIgnoreCase (possibleTagName);
409
410 // XML tags should be case-sensitive, so although this method allows a
411 // case-insensitive match to pass, you should try to avoid this.
412 jassert ((! matches) || tagName == possibleTagName);
413
414 return matches;
415}
416
418{
419 return tagName.upToFirstOccurrenceOf (":", false, false);
420}
421
423{
424 return tagName.fromLastOccurrenceOf (":", false, false);
425}
426
431
433{
434 auto* e = nextListItem.get();
435
436 while (e != nullptr && ! e->hasTagName (requiredTagName))
437 e = e->nextListItem;
438
439 return e;
440}
441
443{
444 jassert (isValidXmlName (newTagName));
445 tagName = StringPool::getGlobalPool().getPooledString (newTagName);
446}
447
448//==============================================================================
450{
451 return attributes.size();
452}
453
454static const String& getEmptyStringRef() noexcept
455{
456 static String empty;
457 return empty;
458}
459
460const String& XmlElement::getAttributeName (const int index) const noexcept
461{
462 if (auto* att = attributes[index].get())
463 return att->name.toString();
464
465 return getEmptyStringRef();
466}
467
468const String& XmlElement::getAttributeValue (const int index) const noexcept
469{
470 if (auto* att = attributes[index].get())
471 return att->value;
472
473 return getEmptyStringRef();
474}
475
476XmlElement::XmlAttributeNode* XmlElement::getAttribute (StringRef attributeName) const noexcept
477{
478 for (auto* att = attributes.get(); att != nullptr; att = att->nextListItem)
479 if (att->name == attributeName)
480 return att;
481
482 return nullptr;
483}
484
486{
487 return getAttribute (attributeName) != nullptr;
488}
489
490//==============================================================================
492{
493 if (auto* att = getAttribute (attributeName))
494 return att->value;
495
496 return getEmptyStringRef();
497}
498
500{
501 if (auto* att = getAttribute (attributeName))
502 return att->value;
503
504 return defaultReturnValue;
505}
506
508{
509 if (auto* att = getAttribute (attributeName))
510 return att->value.getIntValue();
511
512 return defaultReturnValue;
513}
514
516{
517 if (auto* att = getAttribute (attributeName))
518 return att->value.getDoubleValue();
519
520 return defaultReturnValue;
521}
522
524{
525 if (auto* att = getAttribute (attributeName))
526 {
527 auto firstChar = *(att->value.getCharPointer().findEndOfWhitespace());
528
529 return firstChar == '1'
530 || firstChar == 't'
531 || firstChar == 'y'
532 || firstChar == 'T'
533 || firstChar == 'Y';
534 }
535
536 return defaultReturnValue;
537}
538
541 const bool ignoreCase) const noexcept
542{
543 if (auto* att = getAttribute (attributeName))
544 return ignoreCase ? att->value.equalsIgnoreCase (stringToCompareAgainst)
545 : att->value == stringToCompareAgainst;
546
547 return false;
548}
549
550//==============================================================================
552{
553 if (attributes == nullptr)
554 {
555 attributes = new XmlAttributeNode (attributeName, value);
556 }
557 else
558 {
559 for (auto* att = attributes.get(); ; att = att->nextListItem)
560 {
561 if (att->name == attributeName)
562 {
563 att->value = value;
564 break;
565 }
566
567 if (att->nextListItem == nullptr)
568 {
569 att->nextListItem = new XmlAttributeNode (attributeName, value);
570 break;
571 }
572 }
573 }
574}
575
580
582{
583 setAttribute (attributeName, serialiseDouble (number));
584}
585
587{
588 for (auto* att = &attributes; att->get() != nullptr; att = &(att->get()->nextListItem))
589 {
590 if (att->get()->name == attributeName)
591 {
592 delete att->removeNext();
593 break;
594 }
595 }
596}
597
599{
600 attributes.deleteAll();
601}
602
603//==============================================================================
605{
606 return firstChildElement.size();
607}
608
609XmlElement* XmlElement::getChildElement (const int index) const noexcept
610{
611 return firstChildElement [index].get();
612}
613
615{
616 jassert (! childName.isEmpty());
617
618 for (auto* child = firstChildElement.get(); child != nullptr; child = child->nextListItem)
619 if (child->hasTagName (childName))
620 return child;
621
622 return nullptr;
623}
624
626{
627 jassert (! attributeName.isEmpty());
628
629 for (auto* child = firstChildElement.get(); child != nullptr; child = child->nextListItem)
630 if (child->compareAttribute (attributeName, attributeValue))
631 return child;
632
633 return nullptr;
634}
635
637{
638 if (newNode != nullptr)
639 {
640 // The element being added must not be a child of another node!
641 jassert (newNode->nextListItem == nullptr);
642
643 firstChildElement.append (newNode);
644 }
645}
646
648{
649 if (newNode != nullptr)
650 {
651 // The element being added must not be a child of another node!
652 jassert (newNode->nextListItem == nullptr);
653
654 firstChildElement.insertAtIndex (indexToInsertAt, newNode);
655 }
656}
657
659{
660 if (newNode != nullptr)
661 {
662 // The element being added must not be a child of another node!
663 jassert (newNode->nextListItem == nullptr);
664
665 firstChildElement.insertNext (newNode);
666 }
667}
668
675
677 XmlElement* const newNode) noexcept
678{
679 if (newNode != nullptr)
680 {
681 if (auto* p = firstChildElement.findPointerTo (currentChildElement))
682 {
684 delete p->replaceNext (newNode);
685
686 return true;
687 }
688 }
689
690 return false;
691}
692
694 const bool shouldDeleteTheChild) noexcept
695{
696 if (childToRemove != nullptr)
697 {
698 jassert (containsChildElement (childToRemove));
699
700 firstChildElement.remove (childToRemove);
701
703 delete childToRemove;
704 }
705}
706
708 const bool ignoreOrderOfAttributes) const noexcept
709{
710 if (this != other)
711 {
712 if (other == nullptr || tagName != other->tagName)
713 return false;
714
716 {
717 int totalAtts = 0;
718
719 for (auto* att = attributes.get(); att != nullptr; att = att->nextListItem)
720 {
721 if (! other->compareAttribute (att->name, att->value))
722 return false;
723
724 ++totalAtts;
725 }
726
727 if (totalAtts != other->getNumAttributes())
728 return false;
729 }
730 else
731 {
732 auto* thisAtt = attributes.get();
733 auto* otherAtt = other->attributes.get();
734
735 for (;;)
736 {
737 if (thisAtt == nullptr || otherAtt == nullptr)
738 {
739 if (thisAtt == otherAtt) // both nullptr, so it's a match
740 break;
741
742 return false;
743 }
744
745 if (thisAtt->name != otherAtt->name
746 || thisAtt->value != otherAtt->value)
747 {
748 return false;
749 }
750
751 thisAtt = thisAtt->nextListItem;
752 otherAtt = otherAtt->nextListItem;
753 }
754 }
755
756 auto* thisChild = firstChildElement.get();
757 auto* otherChild = other->firstChildElement.get();
758
759 for (;;)
760 {
761 if (thisChild == nullptr || otherChild == nullptr)
762 {
763 if (thisChild == otherChild) // both 0, so it's a match
764 break;
765
766 return false;
767 }
768
769 if (! thisChild->isEquivalentTo (otherChild, ignoreOrderOfAttributes))
770 return false;
771
772 thisChild = thisChild->nextListItem;
773 otherChild = otherChild->nextListItem;
774 }
775 }
776
777 return true;
778}
779
781{
782 firstChildElement.deleteAll();
783}
784
786{
787 for (auto* child = firstChildElement.get(); child != nullptr;)
788 {
789 auto* nextChild = child->nextListItem.get();
790
791 if (child->hasTagName (name))
792 removeChildElement (child, true);
793
794 child = nextChild;
795 }
796}
797
799{
800 return firstChildElement.contains (possibleChild);
801}
802
804{
805 if (this == elementToLookFor || elementToLookFor == nullptr)
806 return nullptr;
807
808 for (auto* child = firstChildElement.get(); child != nullptr; child = child->nextListItem)
809 {
810 if (elementToLookFor == child)
811 return this;
812
813 if (auto* found = child->findParentElementOf (elementToLookFor))
814 return found;
815 }
816
817 return nullptr;
818}
819
820void XmlElement::getChildElementsAsArray (XmlElement** elems) const noexcept
821{
822 firstChildElement.copyToArray (elems);
823}
824
825void XmlElement::reorderChildElements (XmlElement** elems, int num) noexcept
826{
827 auto* e = elems[0];
828 firstChildElement = e;
829
830 for (int i = 1; i < num; ++i)
831 {
832 e->nextListItem = elems[i];
833 e = e->nextListItem;
834 }
835
836 e->nextListItem = nullptr;
837}
838
839//==============================================================================
841{
842 return tagName.isEmpty();
843}
844
845static const String juce_xmltextContentAttributeName ("text");
846
848{
849 jassert (isTextElement()); // you're trying to get the text from an element that
850 // isn't actually a text element.. If this contains text sub-nodes, you
851 // probably want to use getAllSubText instead.
852
853 return getStringAttribute (juce_xmltextContentAttributeName);
854}
855
857{
858 if (isTextElement())
859 setAttribute (juce_xmltextContentAttributeName, newText);
860 else
861 jassertfalse; // you can only change the text in a text element, not a normal one.
862}
863
865{
866 if (isTextElement())
867 return getText();
868
869 if (getNumChildElements() == 1)
870 return firstChildElement.get()->getAllSubText();
871
872 MemoryOutputStream mem (1024);
873
874 for (auto* child = firstChildElement.get(); child != nullptr; child = child->nextListItem)
875 mem << child->getAllSubText();
876
877 return mem.toUTF8();
878}
879
881{
882 if (auto* child = getChildByName (childTagName))
883 return child->getAllSubText();
884
885 return defaultReturnValue;
886}
887
889{
890 auto e = new XmlElement ((int) 0);
891 e->setAttribute (juce_xmltextContentAttributeName, text);
892 return e;
893}
894
896{
897 if (text.isEmpty() || ! isValidXmlNameStartCharacter (text.text.getAndAdvance()))
898 return false;
899
900 for (;;)
901 {
902 if (text.isEmpty())
903 return true;
904
905 if (! isValidXmlNameBodyCharacter (text.text.getAndAdvance()))
906 return false;
907 }
908}
909
911{
913}
914
916{
917 for (auto* child = firstChildElement.get(); child != nullptr;)
918 {
919 auto* next = child->nextListItem.get();
920
921 if (child->isTextElement())
922 removeChildElement (child, true);
923
924 child = next;
925 }
926}
927
928//==============================================================================
929#if JUCE_UNIT_TESTS
930
931class XmlElementTests : public UnitTest
932{
933public:
934 XmlElementTests() : UnitTest ("XmlElement", "XML") {}
935
936 void runTest() override
937 {
938 {
939 beginTest ("Float formatting");
940
941 auto element = std::make_unique<XmlElement> ("test");
942 Identifier number ("number");
943
944 std::map<double, String> tests;
945 tests[1] = "1.0";
946 tests[1.1] = "1.1";
947 tests[1.01] = "1.01";
948 tests[0.76378] = "0.76378";
949 tests[-10] = "-10.0";
950 tests[10.01] = "10.01";
951 tests[0.0123] = "0.0123";
952 tests[-3.7e-27] = "-3.7e-27";
953 tests[1e+40] = "1.0e40";
954 tests[-12345678901234567.0] = "-1.234567890123457e16";
955 tests[192000] = "192000.0";
956 tests[1234567] = "1.234567e6";
957 tests[0.00006] = "0.00006";
958 tests[0.000006] = "6.0e-6";
959
960 for (auto& test : tests)
961 {
962 element->setAttribute (number, test.first);
963 expectEquals (element->getStringAttribute (number), test.second);
964 }
965 }
966 }
967};
968
969static XmlElementTests xmlElementTests;
970
971#endif
972
973} // namespace juce
Holds a resizable array of primitive or copy-by-value objects.
Definition juce_Array.h:60
bool isEmpty() const noexcept
Returns true if the array is empty, false otherwise.
Definition juce_Array.h:226
Array()=default
Creates an empty array.
bool contains(ParameterType elementToLookFor) const
Returns true if the array contains at least one occurrence of an object.
Definition juce_Array.h:357
Wraps a pointer to a null-terminated UTF-8 character string, and provides various methods to operate ...
An output stream that writes into a local file.
Represents a local file or directory.
Definition juce_File.h:45
Represents a string identifier, designed for accessing properties by name.
void deleteAll()
Iterates the list, calling the delete operator on all of its elements and leaving this pointer empty.
ObjectType * get() const noexcept
Returns the item which this pointer points to.
void addCopyOfList(const LinkedListPointer &other)
Creates copies of all the items in another list and adds them to this one.
int size() const noexcept
Returns the number of items in the list.
Writes data to an internal memory buffer, which grows as required.
The base class for streams that write data to some kind of destination.
virtual bool writeByte(char byte)
Writes a single byte to the stream.
A StringPool holds a set of shared strings, which reduces storage overheads and improves comparison s...
static StringPool & getGlobalPool() noexcept
Returns a shared global pool which is used for things like Identifiers, XML parsing.
A simple class for holding temporary references to a string literal or String.
The JUCE String class!
Definition juce_String.h:43
String upToFirstOccurrenceOf(StringRef substringToEndWith, bool includeSubStringInResult, bool ignoreCase) const
Returns the start of this string, up to the first occurrence of a substring.
String fromLastOccurrenceOf(StringRef substringToFind, bool includeSubStringInResult, bool ignoreCase) const
Returns a section of the string starting from the last occurrence of a given substring.
CharPointer_UTF8 CharPointerType
This is the character encoding type used internally to store the string.
Manages a temporary file, which will be deleted when this object is deleted.
This is a base class for classes that perform a unit test.
Used to build a tree of elements representing an XML document.
XmlElement * getNextElementWithTagName(StringRef requiredTagName) const
Returns the next of this element's siblings which has the specified tag name.
void setTagName(StringRef newTagName)
Changes this elements tag name.
void writeToStream(OutputStream &output, StringRef dtdToUse, bool allOnOneLine=false, bool includeXmlHeader=true, StringRef encodingType="UTF-8", int lineWrapLength=60) const
Writes the document to a stream as UTF-8.
void addTextElement(const String &text)
Appends a section of text to this element.
int getNumChildElements() const noexcept
Returns the number of sub-elements in this element.
XmlElement(const String &tagName)
Creates an XmlElement with this tag name.
void insertChildElement(XmlElement *newChildElement, int indexToInsertAt) noexcept
Inserts an element into this element's list of children.
XmlElement * getChildByName(StringRef tagNameToLookFor) const noexcept
Returns the first sub-element with a given tag-name.
bool isTextElement() const noexcept
Returns true if this element is a section of text.
void deleteAllChildElementsWithTagName(StringRef tagName) noexcept
Deletes all the child elements with a given tag name.
void addChildElement(XmlElement *newChildElement) noexcept
Appends an element to this element's list of children.
String getTagNameWithoutNamespace() const
Returns the part of the tag-name that follows any namespace declaration.
double getDoubleAttribute(StringRef attributeName, double defaultReturnValue=0.0) const
Returns the value of a named attribute as floating-point.
const String & getAttributeValue(int attributeIndex) const noexcept
Returns the value of one of the elements attributes.
void prependChildElement(XmlElement *newChildElement) noexcept
Inserts an element at the beginning of this element's list of children.
XmlElement * createNewChildElement(StringRef tagName)
Creates a new element with the given name and returns it, after adding it as a child element.
String getChildElementAllSubText(StringRef childTagName, const String &defaultReturnValue) const
Returns all the sub-text of a named child element.
const String & getText() const noexcept
Returns the text for a text element.
void deleteAllTextElements() noexcept
Removes all the text elements from this element.
~XmlElement() noexcept
Deleting an XmlElement will also delete all of its child elements.
String getAllSubText() const
Returns all the text from this element's child nodes.
bool compareAttribute(StringRef attributeName, StringRef stringToCompareAgainst, bool ignoreCase=false) const noexcept
Compares the value of a named attribute with a value passed-in.
void setText(const String &newText)
Sets the text in a text element.
XmlElement * findParentElementOf(const XmlElement *childToSearchFor) noexcept
Recursively searches all sub-elements of this one, looking for an element which is the direct parent ...
bool isEquivalentTo(const XmlElement *other, bool ignoreOrderOfAttributes) const noexcept
Compares two XmlElements to see if they contain the same text and attributes.
bool getBoolAttribute(StringRef attributeName, bool defaultReturnValue=false) const
Returns the value of a named attribute as a boolean.
void removeAllAttributes() noexcept
Removes all attributes from this element.
static XmlElement * createTextElement(const String &text)
Creates a text element that can be added to a parent element.
String createDocument(StringRef dtdToUse, bool allOnOneLine=false, bool includeXmlHeader=true, StringRef encodingType="UTF-8", int lineWrapLength=60) const
Returns an XML text document that represents this element.
const String & getAttributeName(int attributeIndex) const noexcept
Returns the name of one of the elements attributes.
bool hasAttribute(StringRef attributeName) const noexcept
Checks whether the element contains an attribute with a certain name.
bool containsChildElement(const XmlElement *possibleChild) const noexcept
Returns true if the given element is a child of this one.
bool replaceChildElement(XmlElement *currentChildElement, XmlElement *newChildNode) noexcept
Replaces one of this element's children with another node.
XmlElement * getChildElement(int index) const noexcept
Returns the sub-element at a certain index.
XmlElement & operator=(const XmlElement &)
Creates a (deep) copy of another element.
bool writeToFile(const File &destinationFile, StringRef dtdToUse, StringRef encodingType="UTF-8", int lineWrapLength=60) const
Writes the element to a file as an XML document.
void deleteAllChildElements() noexcept
Deletes all the child elements in the element.
bool hasTagName(StringRef possibleTagName) const noexcept
Tests whether this element has a particular tag name.
void removeAttribute(const Identifier &attributeName) noexcept
Removes a named attribute from the element.
XmlElement * getChildByAttribute(StringRef attributeName, StringRef attributeValue) const noexcept
Returns the first sub-element which has an attribute that matches the given value.
int getNumAttributes() const noexcept
Returns the number of XML attributes this element contains.
void removeChildElement(XmlElement *childToRemove, bool shouldDeleteTheChild) noexcept
Removes a child element.
static bool isValidXmlName(StringRef possibleName) noexcept
Checks if a given string is a valid XML name.
int getIntAttribute(StringRef attributeName, int defaultReturnValue=0) const
Returns the value of a named attribute as an integer.
const String & getStringAttribute(StringRef attributeName) const noexcept
Returns the value of a named attribute.
bool hasTagNameIgnoringNamespace(StringRef possibleTagName) const
Tests whether this element has a particular tag name, ignoring any XML namespace prefix.
String getNamespace() const
Returns the namespace portion of the tag-name, or an empty string if none is specified.
void setAttribute(const Identifier &attributeName, const String &newValue)
Adds a named attribute to the element.