// ____ ______ __ // / __ \ / ____// / // / /_/ // / / / // / ____// /___ / /___ PixInsight Class Library // /_/ \____//_____/ PCL 2.4.23 // ---------------------------------------------------------------------------- // pcl/XML.h - Released 2022-03-12T18:59:29Z // ---------------------------------------------------------------------------- // This file is part of the PixInsight Class Library (PCL). // PCL is a multiplatform C++ framework for development of PixInsight modules. // // Copyright (c) 2003-2022 Pleiades Astrophoto S.L. All Rights Reserved. // // Redistribution and use in both source and binary forms, with or without // modification, is permitted provided that the following conditions are met: // // 1. All redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // 2. All redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // 3. Neither the names "PixInsight" and "Pleiades Astrophoto", nor the names // of their contributors, may be used to endorse or promote products derived // from this software without specific prior written permission. For written // permission, please contact info@pixinsight.com. // // 4. All products derived from this software, in any form whatsoever, must // reproduce the following acknowledgment in the end-user documentation // and/or other materials provided with the product: // // "This product is based on software from the PixInsight project, developed // by Pleiades Astrophoto and its contributors (https://pixinsight.com/)." // // Alternatively, if that is where third-party acknowledgments normally // appear, this acknowledgment must be reproduced in the product itself. // // THIS SOFTWARE IS PROVIDED BY PLEIADES ASTROPHOTO AND ITS CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PLEIADES ASTROPHOTO OR ITS // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, BUSINESS // INTERRUPTION; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; AND LOSS OF USE, // DATA OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // ---------------------------------------------------------------------------- #ifndef __PCL_XML_h #define __PCL_XML_h /// \file pcl/XML.h #include #include #include #include namespace pcl { // ---------------------------------------------------------------------------- /*! * \defgroup xml_parsing_and_generation XML Document Parsing and Generation */ // ---------------------------------------------------------------------------- class PCL_CLASS XMLDocument; class PCL_CLASS XMLElement; // ---------------------------------------------------------------------------- /*! * \class XML * \brief Utility functions and data for %XML document parsing and generation * \ingroup xml_parsing_and_generation */ class PCL_CLASS XML { public: /*! * Default constructor. This constructor is disabled because %XML is not an * instantiable class. */ XML() = delete; /*! * Copy constructor. This constructor is disabled because %XML is not an * instantiable class. */ XML( const XML& ) = delete; /*! * Copy assignment. This operator is disabled because %XML is not an * instantiable class. */ XML& operator =( const XML& ) = delete; /*! * Destructor. This destructor is disabled because %XML is not an * instantiable class. */ ~XML() = delete; /*! * Returns true iff the specified character \a c is either a white space * (\#x20) or a tabulator (#9) character. */ template static bool IsWhiteSpaceChar( T c ) { return c == 0x20 || c == 9; } /*! * Returns true iff the specified character \a c is either a line feed * (\#x0A) or a carriage return (#0D) control character. */ template static bool IsLineBreakChar( T c ) { return c == 0x0A || c == 0x0D; } /*! * Returns true iff the specified character \a c is an %XML space character: * * https://www.w3.org/TR/xml11/#NT-S */ template static bool IsSpaceChar( T c ) { return IsWhiteSpaceChar( c ) || IsLineBreakChar( c ); } /*! * Returns true iff the specified character \a c is an %XML NameStartChar: * * https://www.w3.org/TR/xml11/#NT-NameStartChar */ template static bool IsNameStartChar( T c ) { return c >= T( 'a' ) && c <= T( 'z' ) || c >= T( 'A' ) && c <= T( 'Z' ) || c == T( '_' ) || c == T( ':' ) || c >= 0xC0 && c <= 0xD6 || c >= 0xD8 && c <= 0xF6 || c >= 0xF8 && c <= 0x2FF || c >= 0x370 && c <= 0x37D || c >= 0x37F && c <= 0x1FFF || c >= 0x200C && c <= 0x200D || c >= 0x2070 && c <= 0x218F || c >= 0x2C00 && c <= 0x2FEF || c >= 0x3001 && c <= 0xD7FF || c >= 0xF900 && c <= 0xFDCF || c >= 0xFDF0 && c <= 0xFFFD || uint32( c ) >= 0x10000 && uint32( c ) <= 0xEFFFF; } /*! * Returns true iff the specified character \a c is an %XML NameChar: * * https://www.w3.org/TR/xml11/#NT-NameChar */ template static bool IsNameChar( T c ) { return IsNameStartChar( c ) || c >= T( '0' ) && c <= T( '9' ) || c == T( '-' ) || c == T( '.' ) || c == 0xB7 || c >= 0x0300 && c <= 0x036F || c >= 0x203F && c <= 0x2040; } /*! * Returns true iff the specified character \a c is an %XML RestrictedChar: * * https://www.w3.org/TR/xml11/#NT-RestrictedChar */ template static bool IsRestrictedChar( T c ) { return c >= 0x00 && c <= 0x08 || c >= 0x0B && c <= 0x0C || c >= 0x0E && c <= 0x1F || c >= 0x7F && c <= 0x84 || c >= 0x86 && c <= 0x9F; } /*! * Returns true iff the specified \a name is a valid %XML qualified element * or attribute name: * * https://www.w3.org/TR/xml-names/#ns-qualnames */ static bool IsValidName( const String& name ) { if ( !name.IsEmpty() ) if ( IsNameStartChar( *name ) ) for ( String::const_iterator i = name.Begin(); ; ) { if ( ++i == name.End() ) return true; if ( !IsNameChar( *i ) ) break; } return false; } /*! * Returns a copy of the text fragment defined by the range [i,j) of string * iterators with all leading and trailing space characters removed. */ static String TrimmedSpaces( String::const_iterator i, String::const_iterator j ); /*! * Returns a copy of the specified \a text with all leading and trailing * space characters removed. */ static String TrimmedSpaces( const String& text ); /*! * Returns a copy of the text fragment defined by the range [i,j) of string * iterators with all sequences of one or more space characters replaced * with single white space characters (\#x20). */ static String CollapsedSpaces( String::const_iterator i, String::const_iterator j ); /*! * Returns a copy of the specified \a text with all sequences of one or more * space characters replaced with single white space characters (\#x20). */ static String CollapsedSpaces( const String& text ); /*! * Returns a copy of the text fragment defined by the range [i,j) of string * iterators with all %XML references replaced by their corresponding UTF-16 * characters. * * Both entity and character references are decoded by this function. For * entity references, the entire set of %XML reference names is supported: * * http://www.w3.org/TR/xml-entity-names/ * * Character references are interpreted as defined in the %XML * specification: * * https://www.w3.org/TR/xml11/#NT-CharRef */ static String DecodedText( String::const_iterator i, String::const_iterator j ); /*! * Returns a copy of the specified \a text with all %XML references replaced * by their corresponding UTF-16 characters. * * See DecodedText( String::const_iterator, String::const_iterator ) for a * detailed description. */ static String DecodedText( const String& text ); /*! * Returns a copy of the text fragment defined by the range [i,j) of string * iterators with all occurences of '&', '<', '>' and '"' replaced with the * entity references "amp", "lt", "gt" and "quot", respectively. If \a apos * is true, single quotes will also be replaced with "apos" entities. */ static String EncodedText( String::const_iterator i, String::const_iterator j, bool apos = true ) { return EncodedText( String( i, j ), apos ); } /*! * Returns a copy of the specified \a text with all occurences of '&', '<', * '>' and '"' replaced with the entity references "amp", "lt", "gt" and * "quot", respectively. If \a apos is true, single quotes will also be * replaced with "apos" entities. */ static String EncodedText( const String& text, bool apos = true ); /*! * Returns the Unicode value (encoded as UTF-16) corresponding to an %XML * reference defined by the range [i,j) of string iterators: * * https://www.w3.org/TR/xml11/#NT-Reference * * Both entity and character references are decoded by this function. For * entity references, the entire set of %XML reference names is supported: * * http://www.w3.org/TR/xml-entity-names/ * * Character references are interpreted as defined in the %XML * specification: * * https://www.w3.org/TR/xml11/#NT-CharRef */ static String ReferenceValue( String::const_iterator i, String::const_iterator j ); /*! * Returns the Unicode value (encoded as UTF-16) corresponding to the * specified %XML \a reference. * * See ReferenceValue( String::const_iterator, String::const_iterator ) for * a detailed description. */ static String ReferenceValue( const String& reference ) { return ReferenceValue( reference.Begin(), reference.End() ); } }; // ---------------------------------------------------------------------------- /*! * \class XMLComponent * \brief Root base class of all %XML document components * * %XMLComponent supports the hierarchical structure of an %XML document by * implementing the basic concept of parent element. * * \ingroup xml_parsing_and_generation * \sa XMLNode */ class PCL_CLASS XMLComponent { public: /*! * Default constructor. Constructs a default %XMLComment object with no * parent element. */ XMLComponent() = default; /*! * Copy constructor. */ XMLComponent( const XMLComponent& ) = default; /*! * Returns a pointer to the parent %XML element of this component, or * \c nullptr if this object has no parent element. */ XMLElement* ParentElement() const { return m_parent; } /*! * Returns true iff this is a top-level component. Top-level document * components have no parent elements. */ bool IsTopLevel() const { return m_parent == nullptr; } private: XMLElement* m_parent = nullptr; friend class XMLElement; }; // ---------------------------------------------------------------------------- /*! * \namespace pcl::XMLNodeType * \brief %XML document node types * * * * * * * * * * * *
XMLNodeType::Undefined Undefined %XML node type.
XMLNodeType::ChildNode Signals a child %XML document node - for internal use only.
XMLNodeType::Unknown Represents an unsupported %XML node type.
XMLNodeType::Element An %XML element.
XMLNodeType::Text A text block inside an element's contents.
XMLNodeType::CDATA A CDATA section.
XMLNodeType::ProcessingInstructions A processing instructions (PI) section.
XMLNodeType::PI A synonym to ProcessingInstructions.
XMLNodeType::Comment A comment block.
* * \ingroup xml_parsing_and_generation */ namespace XMLNodeType { enum mask_type { Undefined = 0x00000000, ChildNode = 0x80000000, Unknown = 0x10000000, Element = 0x00000001, Text = 0x00000002, CDATA = 0x00000004, ProcessingInstructions = 0x00000008, Comment = 0x00000010 }; /*! * Returns the name of the specified %XML node \a type ("element", "text", * "comment", etc). */ String AsString( mask_type type ); } /*! * \class pcl::XMLNodeTypes * \brief A collection of %XML node types * \ingroup xml_parsing_and_generation */ typedef Flags XMLNodeTypes; // ---------------------------------------------------------------------------- /*! * \struct XMLNodeLocation * \brief Source code location of a parsed %XML document node * \ingroup xml_parsing_and_generation */ struct XMLNodeLocation { /*! * Zero-based text line number where a parsed node has been identified in * an %XML document, or -1 if text location information is not available. */ int64 line = 0; /*! * Zero-based text column number, counted from the starting character of a * text line, where a parsed node has been identified in an %XML document. * This member is -1 if text location information is not available. * * Note that the value stored in this field is actually a character index, * not necessarily a valid text column number. It is an actual column number * only if the corresponding line of text does not contain tabulator * characters (\#x9). If there are tabulators, there is usually no one-to-one * correspondence between characters and represented text columns. */ int64 column = 0; /*! * Default constructor. Initializes the line and column members to -1, * signaling an undefined source code location. */ XMLNodeLocation() = default; /*! * Constructs an %XMLNodeLocation object with the specified zero-based text * line and column numbers. */ XMLNodeLocation( int line_, int column_ ) : line( line_ ) , column( column_ ) { } /*! * Copy constructor. */ XMLNodeLocation( const XMLNodeLocation& ) = default; /*! * Returns a string representation of this %XMLNodeLocation object in the * form " (line=n offset=m)", where n and m are, respectively, the one-based * line number and zero-based text character offset transported by this * object. This representation is suitable to be included directly in * warning or error messages generated by parsers. * * The line number token won't be generated if the text line number is * undefined (< 0) in this object. Similarly, the offset token won't be * generated if the column member is < 0. If no location information is * available, this member function returns an empty string. */ String ToString() const; }; // ---------------------------------------------------------------------------- /*! * \class XMLNode * \brief Abstract base class of all %XML document node classes * * %XML document nodes can be elements, text, CDATA sections, processing * instructions, comments, and unknown special elements. This class extends the * XMLComponent root base class to implement %XML document node classification * and serialization. * * \ingroup xml_parsing_and_generation */ class PCL_CLASS XMLNode : public XMLComponent { public: /*! * Represents the type of an %XML document node. Supported/valid node types * are defined in the XMLNodeType namespace. */ typedef XMLNodeType::mask_type node_type; /*! * Default constructor. Constructs a default %XMLNode object of the * specified \a type, with no parent element and undefined source code * location. */ XMLNode( node_type type ) : m_type( type ) { } /*! * Copy constructor. * * The newly constructed node will be an \e orphan object, that is, it will * have no parent element even if the source object \a x is a child node. * This reflects the fact that document nodes are unique objects. */ XMLNode( const XMLNode& x ) : m_type( x.NodeType() ) , m_location( x.m_location ) { } /*! * Virtual destructor. */ virtual ~XMLNode() { } /*! * Returns true iff this is a child node of an existing %XML element. */ bool IsChildNode() const { return m_type.IsFlagSet( XMLNodeType::ChildNode ); } /*! * Returns the type of this %XML document node. */ node_type NodeType() const { return static_cast( XMLNodeTypes::flag_type( m_type & unsigned( ~XMLNodeType::ChildNode ) ) ); } /*! * Returns true iff this node is an %XML element. If this member function * returns true, this node can be statically casted to XMLElement. */ bool IsElement() const { return NodeType() == XMLNodeType::Element; } /*! * Returns true iff this node represents an %XML text block. If this member * function returns true, this node can be statically casted to XMLText. */ bool IsText() const { return NodeType() == XMLNodeType::Text; } /*! * Returns true iff this node represents an %XML comment. If this member * function returns true, this node can be statically casted to XMLComment. */ bool IsComment() const { return NodeType() == XMLNodeType::Comment; } /*! * Returns a reference to the (immutable) source code location of this node. */ const XMLNodeLocation& Location() const { return m_location; } /*! * Serializes this document node as an %XML fragment encoded in UTF-8. * * \param text Reference to an 8-bit string to which the UTF-8 * encoded serialization of this node must be appended. * * \param autoFormat True if line break characters (\#x0A) and * indentation strings must be used to improve readability of * the generated %XML code. False if no superfluous white space * should be generated. * * \param indentChar A character used for indentation of generated text * lines, when \a autoFormat is true. This parameter should be * either a white space (' ' or \#x20) or a tabulator ('\\t' or * \#x09) character. * * \param indentSize Number of \a indentChar characters used for each * indentation level, when \a autoFormat is true. * * \param level Recursion level. A value greater than zero denotes * that this function is being called from a parent %XML * element. The recursion level determines the number of * \a indentChar characters prepended to each text line * for indentation, when \a autoFormat is true. */ virtual void Serialize( IsoString& text, bool autoFormat, char indentChar, unsigned indentSize, unsigned level ) const = 0; /*! * Returns true iff a new line character (\#x0A) can be inserted before * serializing this node after the specified \a previous node. */ virtual bool NLAfter( const XMLNode& previous ) const; private: XMLNodeTypes m_type; XMLNodeLocation m_location; friend class XMLDocument; friend class XMLElement; }; /*! * \class pcl::XMLNodeList * \brief Dynamic list of %XML node objects * * %XMLNodeList is used as the internal implementation of element child node * lists and document node lists. In current PCL versions, %XMLNodeList is a * template instantiation of ReferenceArray<> for the XMLNode class. * * \ingroup xml_parsing_and_generation */ typedef ReferenceArray XMLNodeList; // ---------------------------------------------------------------------------- /*! * \class XMLParseError * \brief %XML parsing error with automatic text location information * generation * * The %XMLParseError is useful to generate warning and error messages during * document parsing tasks, with automatic generation of text location * information (when available) and a normalized representation of error * messages. * * \ingroup xml_parsing_and_generation */ class PCL_CLASS XMLParseError : public Error { public: /*! * Constructs an %XMLParseError object with a reference to an XMLNode * instance. * * \param node Reference to the XMLNode object that has caused the * exception. * * \param whileDoing Identifies the parsing action that was taking place. * For example: "Parsing Metadata child Image element". * * \param whatHappened Describes the error that has been detected. For * example: "Missing id attribute". * * This constructor inserts node location information, if available, and * joins the strings appropriately to build an error message. */ XMLParseError( const XMLNode& node, const String& whileDoing, const String& whatHappened ) : Error( whileDoing + node.Location().ToString() + ": " + whatHappened ) { } /*! * Constructs an %XMLParseError object with a reference to an * XMLNodeLocation instance. * * \param where Reference to an XMLNodeLocation object to retrieve * text location information. * * \param whileDoing Identifies the parsing action that was taking place. * For example: "Parsing Metadata child Image element". * * \param whatHappened Describes the error that has been detected. For * example: "Missing id attribute". * * This constructor inserts node location information, if available, and * joins the strings appropriately to build an error message. */ XMLParseError( const XMLNodeLocation& where, const String& whileDoing, const String& whatHappened ) : Error( whileDoing + where.ToString() + ": " + whatHappened ) { } /*! * Copy constructor. */ XMLParseError( const XMLParseError& ) = default; }; // ---------------------------------------------------------------------------- /*! * \class XMLAttribute * \brief %XML element attribute * * The %XMLAttribute class represents an element attribute, as defined by the * Attribute construct: * * https://www.w3.org/TR/xml11/#NT-Attribute * * \ingroup xml_parsing_and_generation */ class PCL_CLASS XMLAttribute : public XMLComponent { public: /*! * Constructs an empty %XML attribute. An empty attribute is ignored for * inclusion in element attribute lists. */ XMLAttribute() = default; /*! * Constructs a new %XMLAttribute object with the specified qualified * \a name and \a value. * * The specified \a name should be a valid %XML qualified name, as defined * by the W3C recommendation: * * https://www.w3.org/TR/xml-names/#ns-qualnames * * However, the \a name is not checked for validity by this constructor, for * performance reasons. Attribute and element names are verified during the * document parsing and generation tasks. */ XMLAttribute( const String& name, const String& value = String() ) : m_name( name ) , m_value( value ) { } /*! * Copy constructor. */ XMLAttribute( const XMLAttribute& ) = default; /*! * Returns a reference to the (immutable) qualified name of this attribute. */ const String& Name() const { return m_name; } /*! * Returns a reference to the (immutable) value of this element attribute. */ const String& Value() const { return m_value; } /*! * Sets a new value for this %XML element attribute. */ void SetValue( const String& text ) { m_value = text; } /*! * Returns an encoded version of the attribute value. All characters that * cannot legally occur in an %XML attribute value are replaced by their * corresponding entity references. */ String EncodedValue() const { return XML::EncodedText( m_value, false/*apos*/ ); } /*! * Equality operator. * * Two %XML element attributes are considered equal if their qualified names * are identical. Note that this restricts valid attribute comparisons to a * particular %XML document. */ bool operator ==( const XMLAttribute& x ) const { return m_name == x.m_name; } /*! * Less-than relational operator. * * To compare %XML element attributes, only their qualified names are taken * into account. Note that this restricts valid attribute comparisons to a * particular %XML document. */ bool operator <( const XMLAttribute& x ) const { return m_name < x.m_name; } private: String m_name; String m_value; }; // ---------------------------------------------------------------------------- /*! * \class XMLAttributeList * \brief Dynamic list of %XML element attributes * * %XMLAttributeList represents a sequence of %XML element attributes in a * start-tag, as defined in the W3C recommendation: * * https://www.w3.org/TR/xml11/#sec-starttags * * %XMLAttributeList is internally implemented as a dynamic array of * XMLAttribute objects. * * \ingroup xml_parsing_and_generation */ class PCL_CLASS XMLAttributeList { public: /*! * Represents the dynamic container class used internally to implement an * %XML element attribute list. */ typedef Array list_implementation; /*! * Represents a mutable %XML element attribute list iterator. */ typedef list_implementation::iterator iterator; /*! * Represents an immutable %XML element attribute list iterator. */ typedef list_implementation::const_iterator const_iterator; /*! * Constructs a new %XMLAttributeList object by parsing the specified * \a text string. * * The specified \a text must be a sequence of zero or more Attribute %XML * definitions pertaining to a start-tag: * * https://www.w3.org/TR/xml11/#NT-STag * * See the Parse() member function for a more detailed description. */ XMLAttributeList( const String& text ) { Parse( text ); } /*! * Default constructor. Constructs an empty %XML attribute list. */ XMLAttributeList() = default; /*! * Copy constructor. */ XMLAttributeList( const XMLAttributeList& ) = default; /*! * Returns the number of element attributes in this list. */ int Length() const { return int( m_list.Length() ); } /*! * Returns true iff this attribute list is empty. */ bool IsEmpty() const { return m_list.IsEmpty(); } /*! * Returns a reference to the immutable element attribute at the specified * zero-based index \a i. No bounds checking is performed: if the specified * index is invalid this function invokes undefined behavior. */ const XMLAttribute& operator []( int i ) const { return m_list[i]; } /*! * Returns an immutable iterator located at the beginning of this element * attribute list. */ const_iterator Begin() const { return m_list.Begin(); } /*! * Returns an immutable iterator located at the end of this element * attribute list. */ const_iterator End() const { return m_list.End(); } #ifndef __PCL_NO_STL_COMPATIBLE_ITERATORS /*! * STL-compatible iteration. Equivalent to Begin() const. */ const_iterator begin() const { return Begin(); } /*! * STL-compatible iteration. Equivalent to End() const. */ const_iterator end() const { return End(); } #endif // !__PCL_NO_STL_COMPATIBLE_ITERATORS /*! * Returns true iff this list contains an element attribute with the * specified qualified \a name. */ bool HasAttribute( const String& name ) const { return m_list.Contains( name ); } /*! * Returns the value of the element attribute with the specified qualified * \a name, or an empty string if this list does not contain such an element * attribute. */ String AttributeValue( const String& name ) const { const_iterator a = m_list.Search( name ); return (a != m_list.End()) ? a->Value() : String(); } /*! * Causes this list to contain an %XML element attribute with the specified * qualified \a name and \a value. * * If an attribute with the same qualified \a name already exists in this * list, then its value will be changed. Otherwise, a new attribute will be * appended to this list. * * This member function ensures that no %XML element can have two or more * attributes with the same qualified name. This constraint is part of the * %XML specification: * * https://www.w3.org/TR/xml11/#sec-starttags * https://www.w3.org/TR/xml-names/#scoping-defaulting */ void SetAttribute( const String& name, const String& value ) { if ( !name.IsEmpty() ) { iterator a = m_list.Search( name ); if ( a == m_list.End() ) m_list.Add( XMLAttribute( name, value ) ); else a->SetValue( value ); } } /*! * Causes this list to contain the specified %XML element \a attribute. * * See SetAttribute( const String&, const String& ) for more information. */ void SetAttribute( const XMLAttribute& attribute ) { if ( !attribute.Name().IsEmpty() ) { iterator a = m_list.Search( attribute ); if ( a == m_list.End() ) m_list.Add( attribute ); else *a = attribute; } } /*! * Insertion operator. Returns a reference to this object. * * This operator is equivalent to SetAttribute( const XMLAttribute& ). */ XMLAttributeList& operator <<( const XMLAttribute& attribute ) { SetAttribute( attribute ); return *this; } /*! * Causes this list to contain the specified \a list of %XML element * attributes. * * For each attribute in the specified \a list, if an attribute with the * same qualified \a name already exists in this list, then its value will * be changed. Otherwise, a new attribute will be appended to this list. * * This member function ensures that no %XML element can have two or more * attributes with the same qualified name. This constraint is part of the * %XML specification: * * https://www.w3.org/TR/xml11/#sec-starttags * https://www.w3.org/TR/xml-names/#scoping-defaulting */ void SetAttributes( const XMLAttributeList& list ) { for ( auto a : list ) SetAttribute( a ); } /*! * Insertion operator. Returns a reference to this object. * * This operator is equivalent to SetAttributes( const XMLAttributeList& ). */ XMLAttributeList& operator <<( const XMLAttributeList& list ) { SetAttributes( list ); return *this; } /*! * Removes the element attribute with the specified qualified \a name, if it * exists in this list. If no attribute with the specified \a name exists, * this member function has no effect. */ void RemoveAttribute( const String& name ) { iterator a = m_list.Search( name ); if ( a != m_list.End() ) m_list.Remove( a ); } /*! * Removes all element attributes in this list, yielding an empty element * attribute list. */ void Clear() { m_list.Clear(); } /*! * Sorts the element attributes in this list in ascending order by comparing * their qualified names. */ void Sort() { m_list.Sort(); } /*! * Parses the specified \a text, encoded as UTF-16, to generate a new list * of %XML element attributes. * * The specified \a text must be a sequence of zero or more Attribute %XML * definitions pertaining to a start-tag, as described in the W3C * recommendation: * * https://www.w3.org/TR/xml11/#NT-STag * * Attribute value normalization is applied to each parsed attribute: * * https://www.w3.org/TR/xml11/#AVNormalize * * In attribute values, all entity and character references are decoded. See * the XML::DecodedText() static function for more information on reference * decoding. Normalization also implies space trimming and compression: all * leading and trailing space characters are removed, and all sequences of * one or more space characters are replaced by single white space * characters (\#x20). */ void Parse( const String& text ); /*! * Performs the %XML serialization of this element attribute list and * appends it to the specified \a text string, encoded in UTF-8. * * The generated serialization is a sequence of zero or more Attribute %XML * definitions pertaining to a start-tag, as described in the W3C * recommendation: * * https://www.w3.org/TR/xml11/#NT-STag */ void Serialize( IsoString& text ) const; private: list_implementation m_list; }; // ---------------------------------------------------------------------------- /*! * \class XMLElement * \brief %XML element * * The %XMLElement class represents an %XML document element: * * https://www.w3.org/TR/xml11/#dt-element * * Elements are the main data holders in the logical design of %XML, following * a hierarchical tree structure. * * \ingroup xml_parsing_and_generation */ class PCL_CLASS XMLElement : public XMLNode { public: /*! * Represents a mutable child node list iterator. */ typedef XMLNodeList::iterator iterator; /*! * Represents an immutable child node list iterator. */ typedef XMLNodeList::const_iterator const_iterator; /*! * A list of child %XML elements. Implemented as a template instantiation of * ReferenceArray<> for the XMLElement class. */ typedef ReferenceArray child_element_list; /*! * Default constructor. Constructs an uninitialized %XMLElement structure. */ XMLElement() : XMLNode( XMLNodeType::Element ) { } /*! * Constructs an empty %XMLElement object with the specified qualified * \a name and \a attributes. */ XMLElement( const String& name, const XMLAttributeList& attributes = XMLAttributeList() ) : XMLNode( XMLNodeType::Element ) , m_name( name ) , m_attributes( attributes ) { } /*! * Constructs an empty %XMLElement object with the specified qualified * \a name and \a attributes, as a child node of the specified \a parent * element. */ XMLElement( XMLElement& parent, const String& name, const XMLAttributeList& attributes = XMLAttributeList() ) : XMLNode( XMLNodeType::Element ) , m_name( name ) , m_attributes( attributes ) { parent.AddChildNode( this ); } /*! * Copy constructor. This constructor is disabled because %XMLElement * represents unique objects. */ XMLElement( const XMLElement& ) = delete; /*! * Copy assignment. This operator is disabled because %XMLElement represents * unique objects. */ XMLElement& operator =( const XMLElement& ) = delete; /*! * Virtual destructor. If this element contains child nodes, all of them * will be destroyed recursively. */ virtual ~XMLElement() { DestroyChildNodes(); } /*! * Returns true iff this is a root %XML element. A root %XML element has no * parent element. * * Note that this member function can return true in two different * situations: when the element has been generated during a document parsing * process (in which case this is an actual document root element), and if * this object has not been initialized yet (because it has been newly * constructed and still has not been associated with an %XML document). */ bool IsRootElement() const { return ParentElement() == nullptr; } /*! * Returns a reference to the (immutable) qualified element name. */ const String& Name() const { return m_name; } /*! * Returns a copy of the list of %XML element attributes. */ XMLAttributeList Attributes() const { return m_attributes; } /*! * Returns true iff this element has one or more attributes defined. */ bool HasAttributes() const { return !m_attributes.IsEmpty(); } /*! * Returns true iff this element has an attribute with the specified * qualified \a name. */ bool HasAttribute( const String& name ) const { return m_attributes.HasAttribute( name ); } /*! * Returns the value of the attribute with the specified qualified \a name * in this element, or an empty string if this element has no such * attribute. */ String AttributeValue( const String& name ) const { return m_attributes.AttributeValue( name ); } /*! * Causes this %XML element to contain an attribute with the specified * qualified \a name and \a value. * * If an attribute with the same qualified \a name already exists in this * element, then its value will be changed. Otherwise, a new attribute will * be created in this element. * * This member function ensures that no %XML element can have two or more * attributes with the same qualified name. This constraint is part of the * %XML specification: * * https://www.w3.org/TR/xml11/#sec-starttags * https://www.w3.org/TR/xml-names/#scoping-defaulting */ void SetAttribute( const String& name, const String& value ) { XMLAttribute a( name, value ); a.m_parent = this; m_attributes.SetAttribute( a ); } /*! * Causes this %XML element to contain the specified \a attribute. * * See SetAttribute( const String&, const String& ) for more information. */ void SetAttribute( const XMLAttribute& attribute ) { XMLAttribute a( attribute ); a.m_parent = this; m_attributes.SetAttribute( a ); } /*! * Insertion operator. Returns a reference to this object. * * This operator is equivalent to SetAttribute( const XMLAttribute& ). */ XMLElement& operator <<( const XMLAttribute& attribute ) { SetAttribute( attribute ); return *this; } /*! * Causes this %XML element to contain the specified \a list of attributes. * * For each attribute in the specified \a list, if an attribute with the * same qualified \a name already exists in this element, then its value * will be changed. Otherwise, a new attribute will be created in this * element. * * This member function ensures that no %XML element can have two or more * attributes with the same qualified name. This constraint is part of the * %XML specification: * * https://www.w3.org/TR/xml11/#sec-starttags * https://www.w3.org/TR/xml-names/#scoping-defaulting */ void SetAttributes( const XMLAttributeList& list ) { for ( auto a : list ) SetAttribute( a ); } /*! * Insertion operator. Returns a reference to this object. * * This operator is equivalent to SetAttributes( const XMLAttributeList& ). */ XMLElement& operator <<( const XMLAttributeList& list ) { SetAttributes( list ); return *this; } /*! * Removes the attribute with the specified qualified \a name, if it exists * in this element. If this element has no attribute with the specified * \a name, this member function has no effect. */ void RemoveAttribute( const String& name ) { m_attributes.RemoveAttribute( name ); } /*! * Removes all existing attributes in this element. */ void ClearAttributes() { m_attributes.Clear(); } /*! * Sorts the existing attributes in this element in ascending order by * comparing their qualified names. */ void SortAttributes() { m_attributes.Sort(); } /*! * Sorts the existing attributes in this element in ascending order. * Ordering of elements is defined such that for any pair a, b of * XMLAttribute objects in this element, the binary predicate p(a,b) is true * iff a precedes b. */ template void SortAttributes( BP p ) { m_attributes.Sort( p ); } /*! * Parses the specified \a text, encoded as UTF-16, to generate a new list * of attributes in this %XML element. The previous list of attributes, if * any, will be replaced by the newly generated list. * * The specified \a text must be a sequence of zero or more Attribute %XML * definitions pertaining to a start-tag, as described in the W3C * recommendation: * * https://www.w3.org/TR/xml11/#NT-STag */ void ParseAttributes( const String& text ) { XMLAttributeList list( text ); ClearAttributes(); SetAttributes( list ); } /*! * Performs the %XML serialization of the attribute list in this element and * appends it to the specified \a text string, encoded in UTF-8. * * The generated serialization is a sequence of zero or more Attribute %XML * definitions pertaining to a start-tag, as described in the W3C * recommendation: * * https://www.w3.org/TR/xml11/#NT-STag */ void SerializeAttributes( IsoString& text ) const { m_attributes.Serialize( text ); } /*! * Returns the number of child nodes in this %XML element. */ int ChildCount() const { return int( m_childNodes.Length() ); } /*! * Returns true iff this is an empty %XML element. An empty element has no * child nodes. */ bool IsEmpty() const { return m_childNodes.IsEmpty(); } /*! * Returns a reference to the immutable child node at the specified * zero-based index \a i. No bounds checking is performed: if the specified * index is invalid this function invokes undefined behavior. */ const XMLNode& operator []( int i ) const { return m_childNodes[i]; } /*! * Returns a reference to the immutable first child node in this element. No * bounds checking is performed: if this element is empty, this function * invokes undefined behavior. */ const XMLNode& First() const { return m_childNodes.First(); } /*! * Returns a reference to the immutable last child node in this element. No * bounds checking is performed: if this element is empty, this function * invokes undefined behavior. */ const XMLNode& Last() const { return m_childNodes.Last(); } /*! * Returns an immutable iterator located at the beginning of the list of * child nodes of this %XML element. */ const_iterator Begin() const { return m_childNodes.Begin(); } /*! * Returns an immutable iterator located at the end of the list of child * nodes of this %XML element. */ const_iterator End() const { return m_childNodes.End(); } #ifndef __PCL_NO_STL_COMPATIBLE_ITERATORS /*! * STL-compatible iteration. Equivalent to Begin() const. */ const_iterator begin() const { return Begin(); } /*! * STL-compatible iteration. Equivalent to End() const. */ const_iterator end() const { return End(); } #endif // !__PCL_NO_STL_COMPATIBLE_ITERATORS #ifndef __PCL_NO_MUTABLE_XML_ELEMENT_ITERATORS /*! * Returns a mutable iterator located at the beginning of the list of child * nodes of this %XML element. */ iterator Begin() { return m_childNodes.Begin(); } /*! * Returns a mutable iterator located at the end of the list of child nodes * of this %XML element. */ iterator End() { return m_childNodes.End(); } /*! * Returns an immutable iterator located at the beginning of the list of * child nodes of this %XML element. */ const_iterator ConstBegin() const { return m_childNodes.ConstBegin(); } /*! * Returns an immutable iterator located at the end of the list of child * nodes of this %XML element. */ const_iterator ConstEnd() const { return m_childNodes.ConstEnd(); } # ifndef __PCL_NO_STL_COMPATIBLE_ITERATORS /*! * STL-compatible iteration. Equivalent to Begin(). */ iterator begin() { return Begin(); } /*! * STL-compatible iteration. Equivalent to End(). */ iterator end() { return End(); } # endif // !__PCL_NO_STL_COMPATIBLE_ITERATORS #endif // !__PCL_NO_MUTABLE_XML_ELEMENT_ITERATORS /*! * Returns true iff this element contains one or more child %XML elements. */ bool HasElements() const { return m_childTypes.IsFlagSet( XMLNodeType::Element ); } /*! * Returns true iff this element contains one or more child text blocks. */ bool HasText() const { return m_childTypes.IsFlagSet( XMLNodeType::Text ); } /*! * Returns true iff this element contains one or more child CDATA sections. */ bool HasCDATA() const { return m_childTypes.IsFlagSet( XMLNodeType::CDATA ); } /*! * Returns true iff this element contains one or more child processing * instructions. */ bool HasProcessingInstructions() const { return m_childTypes.IsFlagSet( XMLNodeType::ProcessingInstructions ); } /*! * Returns true iff this element contains one or more child comment * sections. */ bool HasComments() const { return m_childTypes.IsFlagSet( XMLNodeType::Comment ); } /*! * Returns the text contents of this element, or an empty string if this * element has no text child nodes. * * If this element has two or more text child nodes, the returned value is * the concatenation of all child text nodes. */ String Text() const; /*! * \internal */ void GetChildElements( child_element_list& list, bool recursive ) const { for ( const XMLNode& node : m_childNodes ) if ( node.IsElement() ) { const XMLElement& element = static_cast( node ); list << &element; if ( recursive ) element.GetChildElements( list, recursive ); } } /*! * Returns a list with all child elements of this element. * * if \a recursive is \c true, this member function performs a recursive * search across the entire tree structure rooted at this element. Otherwise * only the direct descendant elements will be returned. */ child_element_list ChildElements( bool recursive = false ) const { child_element_list list; GetChildElements( list, recursive ); return list; } /*! * \internal */ void GetChildElementsByName( child_element_list& list, const String& name, bool recursive ) const { for ( const XMLNode& node : m_childNodes ) if ( node.IsElement() ) { const XMLElement& element = static_cast( node ); if ( element.Name() == name ) { list << &element; if ( recursive ) element.GetChildElementsByName( list, name, recursive ); } } } /*! * Returns a list with all child elements of this element with the specified * \a name. * * if \a recursive is \c true, this member function performs a recursive * search across the entire tree structure rooted at this element. Otherwise * only the direct descendant elements will be returned. */ child_element_list ChildElementsByName( const String& name, bool recursive = false ) const { child_element_list list; GetChildElementsByName( list, name, recursive ); return list; } /*! * \internal */ void GetChildNodesByType( XMLNodeList& list, XMLNodeTypes types, bool recursive ) const { for ( const XMLNode& node : m_childNodes ) if ( types.IsFlagSet( node.NodeType() ) ) { list << &node; if ( recursive ) if ( node.IsElement() ) static_cast( node ).GetChildNodesByType( list, types, recursive ); } } /*! * Returns a list with all child nodes of this element of the specified * \a types. The \a types argument can be an ORed combination of XMLNodeType * enumerated mask values. * * if \a recursive is \c true, this member function performs a recursive * search across the entire tree structure rooted at this element. Otherwise * only the direct descendant nodes will be returned. */ XMLNodeList ChildNodesByType( XMLNodeTypes types, bool recursive = false ) const { XMLNodeList list; GetChildNodesByType( list, types, recursive ); return list; } /*! * \internal */ template void GetChildNodesThat( XMLNodeList& list, UP u, bool recursive ) const { for ( const XMLNode& node : m_childNodes ) if ( u( node ) ) { list << &node; if ( recursive ) if ( node.IsElement() ) static_cast( node ).GetChildNodesThat( list, u, recursive ); } } /*! * Returns a list with all child nodes of this element that satisfy the * specified unary predicate \a u. * * For each child node n in this element, n will be included in the returned * list iff u( n ) returns true. * * if \a recursive is \c true, this member function performs a recursive * search across the entire tree structure rooted at this element. Otherwise * only the direct descendant nodes will be returned. */ template XMLNodeList ChildNodesThat( UP u, bool recursive = false ) const { XMLNodeList list; GetChildNodesThat( list, u, recursive ); return list; } /*! * Appends a child \a node to this %XML element. * * The specified \a node will be owned by this element, which will destroy * it automatically (and recursively) upon destruction. */ void AddChildNode( XMLNode* node ) { m_childNodes << node; node->m_parent = this; node->m_type.SetFlag( XMLNodeType::ChildNode ); m_childTypes.SetFlag( node->NodeType() ); } /*! * Insertion operator: Appends a child \a node to this %XML element. Returns * a reference to this object. * * This operator does the same as AddChildNode( node ). */ XMLElement& operator <<( XMLNode* node ) { AddChildNode( node ); return *this; } /*! * Appends an ordered sequence of child \a nodes to this %XML element. * * After calling this function, all existing \a nodes in the specified list * will be owned by this element, which will destroy them automatically (and * recursively) upon destruction. */ void AddChildNodes( XMLNodeList& nodes ) { for ( XMLNode& node : nodes ) AddChildNode( &node ); } /*! * Insertion operator: Appends an ordered sequence of child \a nodes to this * %XML element. Returns a reference to this object. * * This operator does the same as AddChildNodes( nodes ). */ XMLElement& operator <<( XMLNodeList& nodes ) { AddChildNodes( nodes ); return *this; } /*! * \internal * Appends a new child \a node to this %XML element. * * The specified \a node will be owned by this element, which will destroy * it automatically (and recursively) upon destruction. */ void AddChildNode( XMLNode* node, const XMLNodeLocation& location ) { node->m_location = location; AddChildNode( node ); } /*! * Recursively destroys all existing child nodes in this %XML element, * yielding an empty element. */ void DestroyChildNodes() { m_childNodes.Destroy(); m_childTypes = XMLNodeType::Undefined; } /*! * Releases the child nodes of this %XML element. * * This function returns the (possibly empty) list of child nodes in this * element and causes this object to forget them. The caller will be * responsible for destroying and deallocating all of the returned nodes as * appropriate. After calling this member function, this %XML element will * be empty. */ XMLNodeList ReleaseChildNodes() { XMLNodeList nodes = m_childNodes; m_childNodes.Clear(); m_childTypes = XMLNodeType::Undefined; return nodes; } /*! * Recursively serializes this %XML element and its contents. Appends the * generated %XML source code to the specified 8-bit \a text string, encoded * in UTF-8. * * See XMLNode::Serialize() for information on function parameters. */ void Serialize( IsoString& text, bool autoFormat, char indentChar, unsigned indentSize, unsigned level ) const override; private: String m_name; XMLAttributeList m_attributes; XMLNodeList m_childNodes; XMLNodeTypes m_childTypes = XMLNodeType::Undefined; }; // ---------------------------------------------------------------------------- /*! * \class pcl::XMLElementList * \brief Dynamic list of %XML elements * * %XMLElementList is a template instantiation of ReferenceArray<> for the * XMLElement class. It is used to transport ordered sequences of child element * nodes. See for example XMLElement::ChildElements(). * * \ingroup xml_parsing_and_generation */ typedef XMLElement::child_element_list XMLElementList; // ---------------------------------------------------------------------------- /*! * \class XMLText * \brief %XML text block * * This %XMLText class represents a text entity in an %XML document: * * https://www.w3.org/TR/xml11/#dt-text * * \ingroup xml_parsing_and_generation */ class PCL_CLASS XMLText : public XMLNode { public: /*! * Constructs a new %XMLText object. * * \param text The Unicode text block contents encoded as UTF-16. * * \param preserveSpaces If false, the text block will be transformed by * trimming and collapsing spaces: All leading and trailing * space characters will be removed, and all sequences of one * or more space characters will be replaced by single white * space characters (\#x20). If true, the specified \a text * string will be stored intact. * * \param verbatim If true, the text block will be serialized unencoded, * that is, exactly as is being specified, in the XML * document. No codification of illegal characers such as * quotes and '<' or '>' will be performed. This is useful to * generate special code blocks that must be included * literally, such as <style> or <script> tags in * HTML and SVG documents. * * Besides text contents transformation, space preservation also has an * impact in the way text blocks are serialized as %XML: New line characters * (\#x0A) are never used to separate text blocks from their parent or * sibling nodes when space preservation is enabled. */ XMLText( const String& text, bool preserveSpaces = true, bool verbatim = false ) : XMLNode( XMLNodeType::Text ) , m_text( preserveSpaces ? text : XML::CollapsedSpaces( XML::TrimmedSpaces( text ) ) ) , m_preserveSpaces( preserveSpaces ) , m_verbatim( verbatim ) { } /*! * Copy constructor. */ XMLText( const XMLText& ) = default; /*! * Returns a reference to the (immutable) text string contained by this %XML * text block. The returned string is encoded in UTF-16. */ const String& Text() const { return m_text; } /*! * Returns true iff this text block preserves space characters for * serialization. See the class constructor for more information. */ bool IsPreserveSpaces() const { return m_preserveSpaces; } /*! * Returns an encoded version of this text block. All characters that cannot * legally occur in an %XML text block are replaced by their corresponding * entity references. */ String EncodedText() const { return XML::EncodedText( m_text ); } /*! * Returns a space-transformed version of this text block. * * \param collapse Replace all sequences of one or more space characters * with single white space characters (\#x20). * * \param trim Remove all leading and trailing space characters. */ String SpaceTransformedText( bool collapse, bool trim ) const { String text = m_text; if ( trim ) text = XML::TrimmedSpaces( text ); if ( collapse ) text = XML::CollapsedSpaces( text ); return text; } /*! * Serializes this %XML text block with UTF-8 encoding. * * See XMLNode::Serialize() for information on function parameters. See also * the class constructor for information on space preservation options in * %XML text blocks. */ void Serialize( IsoString& text, bool autoFormat, char indentChar, unsigned indentSize, unsigned level ) const override; /*! * Returns true iff a new line character (\#x0A) can be inserted before * serializing this node after the specified \a previous node. * * In the case of a text block, a new line character can only be inserted * if the block does not preserve space characters. If space preservation is * enabled, new line characters are forbidden at the beginning and end of * the text block serialization. */ bool NLAfter( const XMLNode& previous ) const override { return !m_preserveSpaces; } private: String m_text; // N.B.: This is plain, that is, decoded, text. bool m_preserveSpaces = true; bool m_verbatim = false; }; // ---------------------------------------------------------------------------- /*! * \class XMLCDATA * \brief %XML CDATA section * * The %XMLCDATA class represents a CDATA section in an %XML document: * * https://www.w3.org/TR/xml11/#sec-cdata-sect * * \ingroup xml_parsing_and_generation */ class PCL_CLASS XMLCDATA : public XMLNode { public: /*! * Constructs a new %XMLCDATA object with the specified character \a data * encoded in UTF-16. * * The specified \a data must not contain the sequence "]]>". Any occurrence * of this forbidden sequence will be removed for serialization. */ XMLCDATA( const String& data = String() ) : XMLNode( XMLNodeType::CDATA ) , m_cdata( data ) { } /*! * Copy constructor. */ XMLCDATA( const XMLCDATA& ) = default; /*! * Returns a reference to the (immutable) character data string, encoded as * UTF-16, contained by this CDATA section. */ const String& CData() const { return m_cdata; } /*! * Serializes this %XML CDATA section with UTF-8 encoding. * * See XMLNode::Serialize() for information on function parameters. */ void Serialize( IsoString& text, bool autoFormat, char indentChar, unsigned indentSize, unsigned level ) const override; private: String m_cdata; }; // ---------------------------------------------------------------------------- /*! * \class XMLProcessingInstructions * \brief %XML processing instructions * * The %XMLProcessingInstructions class represents a processing instructions * (PI) tag in an %XML document: * * https://www.w3.org/TR/xml11/#sec-pi * * \ingroup xml_parsing_and_generation */ class XMLProcessingInstructions : public XMLNode { public: /*! * Constructs a new %XMLProcessingInstructions object with the specified * \a target name and \a instructions string, both encoded in UTF-16. * * The specified \a instructions string must not contain the sequence "?>". * Any occurrence of this forbidden sequence will be removed for * serialization. */ XMLProcessingInstructions( const String& target, const String& instructions ) : XMLNode( XMLNodeType::ProcessingInstructions ) , m_target( target ) , m_instructions( instructions ) { } /*! * Copy constructor. */ XMLProcessingInstructions( const XMLProcessingInstructions& ) = default; /*! * Returns a reference to the (immutable) instructions target name. */ const String& Target() const { return m_target; } /*! * Returns a reference to the (immutable) instructions string. */ const String& Instructions() const { return m_instructions; } /*! * Serializes this %XML PI section with UTF-8 encoding. * * See XMLNode::Serialize() for information on function parameters. */ void Serialize( IsoString& text, bool autoFormat, char indentChar, unsigned indentSize, unsigned level ) const override; private: String m_target; String m_instructions; }; // ---------------------------------------------------------------------------- /*! * \class XMLComment * \brief %XML comment section * * The %XMLComment class represents a comment in an %XML document: * * https://www.w3.org/TR/xml11/#sec-comments * * \ingroup xml_parsing_and_generation */ class PCL_CLASS XMLComment : public XMLNode { public: /*! * Constructs a new %XMLComment object with the specified \a comment string * encoded in UTF-16. * * The specified \a comment must not contain the sequence "--" or end with * a '-' character. Any occurrence of these forbidden sequences will be * removed for serialization. */ XMLComment( const String& comment ) : XMLNode( XMLNodeType::Comment ) , m_comment( comment ) { } /*! * Copy constructor. */ XMLComment( const XMLComment& ) = default; /*! * Returns a reference to the (immutable) comment string. */ const String& Comment() const { return m_comment; } /*! * Serializes this %XML comment section with UTF-8 encoding. * * See XMLNode::Serialize() for information on function parameters. */ void Serialize( IsoString& text, bool autoFormat, char indentChar, unsigned indentSize, unsigned level ) const override; private: String m_comment; }; // ---------------------------------------------------------------------------- /*! * \class XMLUnknownElement * \brief Unsupported or invalid %XML element * * %XMLUnknownElement represents an invalid or unrecognized %XML element * retrieved while parsing an %XML document. In the current PCL implementation, * an %XMLUnknownElement object is generated if the parser finds an element * whose start-tag begins with the " * XMLParserOption::IgnoreComments Do not add comment nodes to the DOM. * XMLParserOption::IgnoreUnknownElements Do not add unknown/invalid elements to the DOM. * XMLParserOption::IgnoreStrayCharacters Be tolerant of non-space characters outside markup. * XMLParserOption::NormalizeTextSpaces Trim and collapse spaces in all child text nodes. * * * \ingroup xml_parsing_and_generation */ namespace XMLParserOption { enum mask_type { IgnoreComments = 0x00000001, IgnoreUnknownElements = 0x00000002, IgnoreStrayCharacters = 0x00000004, NormalizeTextSpaces = 0x00000008 }; } /*! * \class pcl::XMLParserOptions * \brief A collection of %XML document parsing options * \ingroup xml_parsing_and_generation */ typedef Flags XMLParserOptions; // ---------------------------------------------------------------------------- /*! * \class XMLDocument * \brief %XML document parsing and generation * * %XMLDocument implements parsing and generation of well-formed %XML * documents. * * The Parse() member function reads and interprets a Unicode text string to * generate a read-only document object model (DOM) that represents the data * entities defined by a well-formed %XML document. The DOM can be inspected * with several member functions of the %XMLDocument class. All %XML nodes and * elements in a document can be visited recursively with specialized accessor * functions and iterators. See the Begin() and End() functions (and their * STL-compatible equivalents, begin() and end()), as well as XML(), DocType(), * RootElement(), and operator []( int ), among others. * * For generation of %XML documents, the Serialize() member function builds a * new document as a Unicode string encoded in UTF-8. The document's root node * and several nodes and critical components must be defined before document * generation - see the SetXML(), SetDocType(), AddNode() and SetRootElement() * member functions. * * For general information on %XML, the authoritative sources are the W3C * recommendations: * * https://www.w3.org/TR/xml/ * https://www.w3.org/TR/xml11/ * https://www.w3.org/TR/xml-names/ * * The following example shows how an existing document can be parsed as a new * %XMLDocument object, and then a new %XML document can be generated and * written to a disk file, all in just three source code lines: * * \code * XMLDocument xml; * xml.Parse( File::ReadTextFile( "/path/to/file.xml" ).UTF8ToUTF16() ); * File::WriteTextFile( "/tmp/test.xml", xml.Serialize() ); * \endcode * * In this case the new document is generated without superfluous space * characters. To enable automatic indentation of text lines, see the * EnableAutoFormatting(), SetIndentSize() and EnableIndentTabs() member * functions. * * The following example: * * \code * XMLElement* e1 = new XMLElement( "Foo", XMLAttributeList() << XMLAttribute( "version", "1.0" ) ); * * XMLElement* e2 = new XMLElement( "Bar" ); * *e2 << new XMLElement( "bar_child_1" ) * << new XMLElement( "bar_child_2" ); * * XMLElement* e3 = new XMLElement( "FooBar" ); * *e3 << new XMLText( "This is FooBar." ); * * *e1 << e2 << e3; * * XMLDocument xml; * xml.SetXML( "1.0" ); * xml.SetRootElement( e1 ); * xml.EnableAutoFormatting(); * xml.SerializeToFile( "/tmp/foobar.xml" ); * \endcode * * generates this %XML file in /tmp/foobar.xml: * * \code * * * * * * * This is FooBar. * * \endcode * * \ingroup xml_parsing_and_generation */ class PCL_CLASS XMLDocument { public: /*! * Represents a mutable child node list iterator. */ typedef XMLNodeList::iterator iterator; /*! * Represents an immutable child node list iterator. */ typedef XMLNodeList::const_iterator const_iterator; /*! * Represents an option to control the %XML parser behavior. Valid options * are defined in the XMLParserOption namespace. */ typedef XMLParserOption::mask_type parser_option; /*! * Default constructor. Constructs an empty %XML document. * * For serialization of XML documents, this constructor defines the * following default settings: * * \li Auto-formatting disabled. * \li Use space characters (\#x20) for indentation. * \li Indentation size = 3 spaces. */ XMLDocument() = default; /*! * Virtual destructor. Recursively destroys all %XML elements, declarations * and auxiliary data associated with this object. */ virtual ~XMLDocument() { m_nodes.Destroy(); m_root = nullptr; RemoveElementFilter(); } /*! * Copy constructor. This constructor is disabled because %XMLDocument * represents unique objects. */ XMLDocument( const XMLDocument& ) = delete; /*! * Copy assignment. This operator is disabled because %XMLDocument * represents unique objects. */ XMLDocument& operator =( const XMLDocument& ) = delete; /*! * Returns a reference to the (immutable) %XML declaration object associated * with this document. */ const XMLDeclaration& XML() const { return m_xml; } /*! * Defines an %XML declaration in this %XML document. */ void SetXML( const XMLDeclaration& xml ) { m_xml = xml; } /*! * Defines an %XML declaration in this %XML document with the specified * \a version, \a encoding and \a standalone attributes. */ void SetXML( const String& version = "1.0", const String& encoding = "UTF-8", bool standalone = false ) { SetXML( XMLDeclaration( version, encoding, standalone ) ); } /*! * Returns a reference to the (immutable) %XML document type declaration * object associated with this document. */ const XMLDocTypeDeclaration& DocType() const { return m_docType; } /*! * Associates a new %XML document type declaration object with this %XML * document. */ void SetDocType( const XMLDocTypeDeclaration& docType ) { m_docType = docType; } /*! * Returns a pointer to the (immutable) root element of this %XML document. * If there is no root element, for example when this is an uninitialized * %XMLDocument instance, this function returns \c nullptr. * * \sa ReleaseRootElement(), SetRootElement() */ const XMLElement* RootElement() const { return m_root; } /*! * Releases the root element of this %XML document. * * This function returns the root element and causes this object to forget * it. The caller will be responsible for destroying and deallocating the * returned XMLElement instance as appropriate. This function performs an * implicit call to Clear(), so the document will be empty after calling it. * * If there is no root element, for example when this is an uninitialized * %XMLDocument instance, this function returns \c nullptr. * * \sa RootElement(), SetRootElement() */ XMLElement* ReleaseRootElement() { XMLElement* root = m_root; m_nodes.RemovePointer( m_root ); Clear(); return root; } /*! * Returns the number of nodes in this %XML document, or zero if this is an * empty or uninitialized %XMLDocument object. */ int NodeCount() const { return int( m_nodes.Length() ); } /*! * Returns true iff this is an empty %XML document. An empty document has no * %XML nodes. */ bool IsEmpty() const { return m_nodes.IsEmpty(); } /*! * Returns a reference to the (immutable) document node at the specified * zero-based index \a i. No bounds checking is performed: if the specified * index is invalid, this function invokes undefined behavior. */ const XMLNode& operator []( int i ) const { return m_nodes[i]; } /*! * Returns an immutable iterator located at the beginning of the list of * nodes of this %XML document. */ const_iterator Begin() const { return m_nodes.Begin(); } /*! * Returns an immutable iterator located at the end of the list of * nodes of this %XML document. */ const_iterator End() const { return m_nodes.End(); } #ifndef __PCL_NO_STL_COMPATIBLE_ITERATORS /*! * STL-compatible iteration. Equivalent to Begin() const. */ const_iterator begin() const { return Begin(); } /*! * STL-compatible iteration. Equivalent to End() const. */ const_iterator end() const { return End(); } #endif // !__PCL_NO_STL_COMPATIBLE_ITERATORS /*! * Appends a new top-level %XML node to this document. * * If the specified \a node already belongs to an %XMLDocument object, or if * a null pointer is specified, this member function will throw an Error * exception. * * The specified \a node will be appended to the current list of document * nodes. If there is a root element in this document, the new \a node will * be appended after the root element. * * The \a node will be owned by this document object, which will destroy and * deallocate it automatically when appropriate. */ void AddNode( XMLNode* node ); /*! * Insertion operator. Returns a reference to this %XMLDocument object. * * This operator is equivalent to AddNode( XMLNode* ). */ XMLDocument& operator <<( XMLNode* node ) { AddNode( node ); return *this; } /*! * Sets the root element of this %XML document. * * If the specified \a element already belongs to an %XMLDocument object, if * a null pointer is specified, or if a root node has already been defined * for this document, this member function will throw an Error exception. * * The specified \a element will be appended to the current list of document * nodes. The \a element will be owned by this document object, which will * destroy and deallocate it automatically when appropriate. * * \sa RootElement(), ReleaseRootElement() */ void SetRootElement( XMLElement* element ); /*! * Destroys and deallocates all nodes and elements in this %XML document * object, and initializes all internal structures to a default state, * yielding an uninitialized object. * * If there is an element filter or a set of parser options defined for this * object, they are preserved by this function. See RemoveElementFilter() to * remove a filter set by a previous call to SetElementFilter(). See also * ClearParserOptions() to reset parser options set by previous calls to * SetParserOption(). */ void Clear(); /*! * Sets a new element filter for this object. The specified object will be * owned by this %XMLDocument instance, which will destroy and deallocate it * when appropriate. * * See XMLElementFilter for a complete description of the element filtering * functionality. See RemoveElementFilter() to remove the element filter * set by this function. */ void SetElementFilter( XMLElementFilter* filter ) { delete m_filter, m_filter = filter; } /*! * Removes an element filter set by a previous call to SetElementFilter(). * If no filter has been defined for this object, this function has no * effect. */ void RemoveElementFilter() { SetElementFilter( nullptr ); } /*! * Enables or disables an %XML document parser option for this object. Valid * options are defined in the XMLParserOption namespace. See * ClearParserOptions() to reset all parser options to a default state. */ void SetParserOption( parser_option option, bool on = true ) { m_parserOptions.SetFlag( option, on ); } /*! * Sets the specified parser \a options. Valid options are defined in the * XMLParserOption namespace. See ClearParserOptions() to reset all parser * options to a default state. */ void SetParserOptions( XMLParserOptions options ) { m_parserOptions = options; } /*! * Resets all parser options defined for this object by a previous call to * SetParserOption() or SetParserOptions(). */ void ClearParserOptions() { m_parserOptions.Clear(); } /*! * %XML document parser. Reads and interprets the specified Unicode \a text * string, which must be encoded in UTF-16, as a well-formed %XML document. * * This member function generates a document object model (DOM) to represent * the data entities defined by the source %XML document. The DOM can then * be inspected with several member functions of the %XMLDocument class. All * %XML nodes and elements can be visited recursively with specialized * iterators. See the Begin() and End() functions (and their STL-compatible * equivalents, begin() and end()), as well as XML(), DocType(), * RootElement() and operator []( int ), among others. */ void Parse( const String& text ); /*! * Returns true iff the auto-formatting feature is enabled for %XML * serialization with this %XMLDocument object. * * When auto-formatting is enabled, ignorable line breaks (\#x0A) and white * space characters (either spaces (\#x20) or tabulators (\#x09)) are used * to separate %XML nodes and to indent text lines, respectively, improving * readability of generated %XML code. When auto-formatting is disabled, no * superfluous white space characters are generated. The only exception is * XMLText child nodes with space preservation enabled, which always ignore * all indentation and formatting settings in order to reproduce their text * contents without modification. * * The auto-formatting feature is always disabled by default for newly * constructed %XMLDocument objects. This is because the main purpose and * utility of %XMLDocument is parsing and generation of %XML documents * intended for automated data management, without direct user intervention. * Auto-formatting is only useful for human readability of %XML source code. */ bool IsAutoFormatting() const { return m_autoFormatting; } /*! * Enables the auto-formatting feature for generation of %XML code. See * IsAutoFormatting() for more information. */ void EnableAutoFormatting( bool enable = true ) { m_autoFormatting = enable; } /*! * Disables the auto-formatting feature for generation of %XML code. See * IsAutoFormatting() for more information. */ void DisableAutoFormatting( bool disable = true ) { EnableAutoFormatting( !disable ); } /*! * Returns the number of space characters (\#x20) used for each indentation * level of text lines, when the auto-formatting feature is enabled and * space characters are used for indentation. * * When tabulator characters (\#x09) are used for indentation, this setting * is ignored and a single tabulator is always used for each indentation * level. See IsAutoFormatting() and SetIndentSize() for more information. */ int IndentSize() const { return m_indentSize; } /*! * Sets the number of indentation space characters. * * \param indentSize Number of space characters (\#x20) used for a level * of indentation of text lines in generated %XML code, * when the auto-formatting feature is enabled and * space characters are used for indentation. The valid * range of values is from zero (for no indentation) to * 8 characters. * * When the indentation size is zero and auto-formatting is enabled, each * document node is generated in a separate line without any indentation. * XMLText child nodes with space preservation enabled will always ignore * all indentation and formatting settings, in order to reproduce their text * contents without modification. * * When tabulator characters (\#x09) are used for indentation, this setting * is ignored and a single tabulator character is always used for each * indentation level. * * The default indentation size is 3 for newly constructed %XMLDocument * objects. */ void SetIndentSize( int indentSize ) { m_indentSize = Range( indentSize, 0, 8 ); } /*! * Returns true if tabulator characters (\#x09) are used for indentation of * text lines, when the auto-formatting feature is enabled. Returns false if * space characters (\#x20) are used for indentation. * * By default, text indentation is always performed using space characters * by newly constructed %XMLDocument objects. */ bool IsIndentTabs() const { return m_indentTabs; } /*! * Enables the use of tabulator characters (\#x09) for indentation. See * IsIndentTabs() for more information. */ void EnableIndentTabs( bool enable = true ) { m_indentTabs = enable; } /*! * Disables the use of tabulator characters (\#x09) for indentation. See * IsIndentTabs() for more information. */ void DisableIndentTabs( bool disable = true ) { EnableIndentTabs( !disable ); } /*! * Serializes this %XML document. Returns the generated serialization as a * Unicode string encoded in UTF-8. * * To serialize a well-formed %XML document, this object must be initialized * first by defining a root element (see SetRootElement()) and other * document nodes, as necessary (see SetXML(), SetDocType(), and AddNode()). * * For formatting and indentation settings, see IsAutoFormatting(), * IndentSize() and IsIndentTabs(). */ IsoString Serialize() const; /*! * Serializes this %XML document and writes the result to a file at the * specified \a path with UTF-8 encoding. * * See Serialize() for more information. * * \warning If a file already exists at the specified path, its previous * contents will be lost after calling this function. */ void SerializeToFile( const String& path ) const; private: XMLDeclaration m_xml; XMLDocTypeDeclaration m_docType; XMLNodeList m_nodes; XMLElement* m_root = nullptr; XMLElementFilter* m_filter = nullptr; XMLParserOptions m_parserOptions; XMLNodeLocation m_location; bool m_autoFormatting = false; bool m_indentTabs = false; int m_indentSize = 3; }; // ---------------------------------------------------------------------------- } // pcl #endif // __PCL_XML_h // ---------------------------------------------------------------------------- // EOF pcl/XML.h - Released 2022-03-12T18:59:29Z