Represents an XML node, such as an element, text, or comment, belonging to an donner::xml::XMLDocument. More...
#include "donner/base/xml/XMLNode.h"
Classes | |
| struct | ProjectedTextChild |
| Owning value and current source span for one deliberately projected-out text child. More... | |
Public Types | |
| enum class | Type : uint8_t { Document , Element , Data , CData , Comment , DocType , ProcessingInstruction , XMLDeclaration } |
| Node type, use type() to query the value. To create nodes of different types, use the relevant static method constructor, such as CreateElementNode and CreateCommentNode. More... | |
Public Member Functions | |
| XMLNode (const XMLNode &other) | |
| Create another reference to the same XMLNode. | |
| XMLNode (XMLNode &&other) noexcept | |
| Move constructor. | |
| ~XMLNode () noexcept=default | |
| Destructor. | |
| XMLNode & | operator= (const XMLNode &other) |
| Create another reference to the same XMLNode. | |
| XMLNode & | operator= (XMLNode &&other) noexcept |
| Move assignment operator. | |
| Type | type () const |
| Get the type of this node. | |
| const XMLQualifiedName & | tagName () const |
| Get the XML qualified tag name for this node. | |
| EntityHandle | entityHandle () const |
| Get the underlying EntityHandle, for advanced use-cases that require direct access to the ECS. | |
| std::optional< RcString > | value () const |
| Get the value of this node, which depends on the node type. | |
| void | setValue (const RcStringOrRef &value) |
| Set the value of this node. | |
| bool | hasAttribute (const XMLQualifiedNameRef &name) const |
| Returns true if the element has an attribute with the given name. | |
| std::optional< RcString > | getAttribute (const XMLQualifiedNameRef &name) const |
| Get the value of an attribute, if it exists. | |
| std::optional< SourceRange > | getNodeLocation () const |
| Get the location of this node in the input string. | |
| std::optional< SourceRange > | getOpeningTagLocation () const |
| Get this node's opening tag/source prefix location. | |
| std::optional< SourceRange > | getClosingTagLocation () const |
| Get this node's closing tag/source suffix location. | |
| std::optional< SourceRange > | getValueLocation () const |
| Get this node's value source location. | |
| std::optional< SourceRange > | getAttributeLocation (std::string_view xmlInput, const XMLQualifiedNameRef &name) const |
| Get the location of an attribute in the input string. | |
| std::optional< XMLAttributeSourceLocation > | getAttributeSourceLocation (const XMLQualifiedNameRef &name) const |
| Get resolved source metadata for an attribute. | |
| void | setAttributeSourceLocation (const XMLQualifiedNameRef &name, SourceRange fullRange, SourceRange valueRange, char quote) |
| Store source metadata for an attribute using the document source store. | |
| void | clearAttributeSourceLocation (const XMLQualifiedNameRef &name) |
| Clear source metadata for an attribute. | |
| SmallVector< XMLQualifiedNameRef, 10 > | attributes () const |
| Get the list of attributes for this element. | |
| std::optional< RcString > | getNamespaceUri (const RcString &prefix) const |
| Get the namespace URI of an attribute prefix, if it exists. | |
| void | setAttribute (const XMLQualifiedNameRef &name, std::string_view value) |
| Set the value of an XML attribute, adding the attribute if it does not exist. | |
| void | removeAttribute (const XMLQualifiedNameRef &name) |
| Remove an attribute and clear its source metadata. | |
| std::optional< XMLNode > | parentElement () const |
| Get this element's parent, if it exists. | |
| std::optional< XMLNode > | firstChild () const |
| Get the first child of this element that is part of the XML document, if it exists. | |
| std::optional< XMLNode > | lastChild () const |
| Get the last child of this element that is part of the XML document, if it exists. | |
| std::optional< XMLNode > | previousSibling () const |
| Get the previous sibling of this element that is part of the XML document, if it exists. | |
| std::optional< XMLNode > | nextSibling () const |
| Get the next sibling of this element that is part of the XML document, if it exists. | |
| void | insertBefore (const XMLNode &newNode, std::optional< XMLNode > referenceNode) |
Insert newNode as a child, before referenceNode. | |
| void | appendChild (const XMLNode &child) |
Append child as a child of the current node. | |
| void | replaceChild (const XMLNode &newChild, const XMLNode &oldChild) |
Replace oldChild with newChild in the tree, removing oldChild and inserting newChild in its place. | |
| void | removeChild (const XMLNode &child) |
Remove child from this node. | |
| void | remove () |
| Remove this node from its parent, if it has one. | |
| void | removeForProjection () |
| Internal projection removal after a consumer captures a non-element child. Text nodes retain source provenance for incremental reconciliation; ordinary tree edits use remove(). | |
| std::vector< ProjectedTextChild > | projectedTextChildren () const |
| Return current projected-out text snapshots, ordered by source. They remain valid even after the original node is collected. Tree/value mutations invalidate matching provenance. | |
| std::optional< FileOffset > | sourceStartOffset () const |
| Get the source offset of where this node starts in the XML document source (if this node was instantiated by XMLParser). | |
| void | setSourceStartOffset (FileOffset offset) |
| Set the source offset of where this node starts in the XML document source. | |
| std::optional< FileOffset > | sourceEndOffset () const |
| Get the source offset of where this node ends in the XML document source (if this node was instantiated by XMLParser). | |
| void | setSourceEndOffset (FileOffset offset) |
| Set the source offset of where this node ends in the XML document source. | |
| void | setOpeningTagLocation (SourceRange range) |
| Store this node's opening tag/source prefix location. | |
| void | clearOpeningTagLocation () |
| Clear this node's opening tag/source prefix location. | |
| void | setClosingTagLocation (SourceRange range) |
| Store this node's closing tag/source suffix location. | |
| void | clearClosingTagLocation () |
| Clear this node's closing tag/source suffix location. | |
| void | setValueLocation (SourceRange range) |
| Store this node's value source location. | |
| void | clearValueLocation () |
| Clear this node's value source location. | |
| void | clearSourceLocation () |
| Clear this node's source location and invalidate any backing source anchors. | |
| RcString | serializeToString (int indentLevel=0, bool prettyPrint=true) const |
| Serialize this node to an XML string. | |
| bool | operator== (const XMLNode &other) const |
| Returns true if the two XMLNode handles reference the same node. | |
| bool | operator!= (const XMLNode &other) const |
| Returns true if the two XMLNode handles reference different nodes. | |
Static Public Member Functions | |
| static XMLNode | CreateElementNode (XMLDocument &document, const XMLQualifiedNameRef &tagName) |
Create a new XML node for an element bound to document. | |
| static XMLNode | CreateElementNodeOn (XMLDocument &document, EntityHandle handle, const XMLQualifiedNameRef &tagName) |
Create an XML element node facade on an existing entity in document. | |
| static XMLNode | CreateDataNode (XMLDocument &document, const RcStringOrRef &value) |
Create a new XML node for text data bound to document, with a given value. | |
| static XMLNode | CreateCDataNode (XMLDocument &document, const RcStringOrRef &value) |
Create a new XML node for a CDATA section bound to document, with a given value. | |
| static XMLNode | CreateCommentNode (XMLDocument &document, const RcStringOrRef &value) |
Create a new XML node for a comment bound to document, with a given value. | |
| static XMLNode | CreateDocTypeNode (XMLDocument &document, const RcStringOrRef &value) |
Create a new XML node for a document type declaration bound to document, with a given value. | |
| static XMLNode | CreateProcessingInstructionNode (XMLDocument &document, const RcStringOrRef &target, const RcStringOrRef &value) |
Create a new XML node for a processing instruction bound to document, with a given target and value. | |
| static XMLNode | CreateXMLDeclarationNode (XMLDocument &document) |
Create a new XML node for an XML declaration bound to document. | |
| static std::optional< XMLNode > | TryCast (EntityHandle entity) |
| Try to cast to an XMLNode from a raw Entity. | |
Protected Member Functions | |
| XMLNode (EntityHandle handle) | |
| Internal constructor to create an XMLNode from an EntityHandle. | |
| Registry & | registry () const |
| Get the underlying ECS Registry, which holds all data for the document, for advanced use. | |
| EntityHandle | toHandle (Entity entity) const |
| Convert an Entity to an EntityHandle, for advanced use. | |
| std::optional< XMLNode > | toOptionalNode (Entity entity) const |
| Wrap an Entity resolved by a tree accessor, for advanced use. | |
Static Protected Member Functions | |
| static XMLNode | CreateDocumentNode (XMLDocument &document) |
| Create an XMLNode for the root node of a document. | |
| static Entity | CreateEntity (Registry ®istry, Type type, const XMLQualifiedNameRef &tagName="") |
Create an Entity for a node of type. | |
Protected Attributes | |
| EntityHandle | handle_ |
| The underlying ECS Entity for this element, which holds all data. | |
Friends | |
| class | XMLDocument |
| std::ostream & | operator<< (std::ostream &os, const Type &type) |
| Ostream output operator. | |
Represents an XML node, such as an element, text, or comment, belonging to an donner::xml::XMLDocument.
See donner::xml::XMLNode::Type for the node types.
Each XMLNode may only belong to a single document, and each document can have only one root. XMLDocument is responsible for managing the lifetime of all elements in the document, by storing a shared pointer to the internal Registry data-store.
Data is stored using the Entity Component System (Entity Component System (ECS)) pattern, which is a data-oriented design optimized for fast data access and cache locality, particularly during rendering.
XMLDocument and XMLNode provide a facade over the ECS, and surface a familiar Document Object Model (DOM) API to traverse and manipulate the document tree, which is internally stored within Components in the ECS. This makes XMLNode a thin wrapper around an Entity, making the object lightweight and usable on the stack.
| struct donner::xml::XMLNode::ProjectedTextChild |
|
strong |
Node type, use type() to query the value. To create nodes of different types, use the relevant static method constructor, such as CreateElementNode and CreateCommentNode.
| Enumerator | |
|---|---|
| Document | Document node, which is the root of the document tree. This is created automatically by donner::xml::XMLDocument. tagName() and value() are empty. |
| Element | Element node, representing a regular XML tag, such as <svg>. tagName() is the tag name. The parser sets value() to the text of each data child as it reads it, so it holds the last one. |
| Data | Data node, containing verbatim text. value() contains the data, and tagName() is empty. |
| CData | CDATA node, such as <![CDATA[ ... ]]> . value() contains the data, and tagName() is empty. |
| Comment | Comment node, such as <!-- ... -->. value() contains the comment text, and tagName() is empty. |
| DocType | Document Type Declaration (DTD) node, such as <!DOCTYPE ...>. tagName() is empty, and value() contains the contents of the node.
|
| ProcessingInstruction | Processing Instruction (PI) node, such as <?php ... ?>. tagName() is the PI target, e.g. "php". value() contains the remaining content. |
| XMLDeclaration | XML Declaration node, such as <?xml ... ?>. This is a special case of donner::xml::XMLNode::Type::ProcessingInstruction with target "xml"; contents are parsed as attributes. tagName() and value() are empty. |
|
explicitprotected |
Internal constructor to create an XMLNode from an EntityHandle.
| handle | EntityHandle to wrap. |
| void donner::xml::XMLNode::appendChild | ( | const XMLNode & | child | ) |
Append child as a child of the current node.
If child is already in the tree, it is first removed from its parent. However, if inserting the child will create a cycle, the behavior is undefined.
| child | Node to append. |
| void donner::xml::XMLNode::clearAttributeSourceLocation | ( | const XMLQualifiedNameRef & | name | ) |
Clear source metadata for an attribute.
| name | Name of the attribute to clear. |
| void donner::xml::XMLNode::clearSourceLocation | ( | ) |
Clear this node's source location and invalidate any backing source anchors.
This is used when a source-backed node is detached from the document so stale callers cannot resolve the removed node to a collapsed range at the deletion point.
|
static |
Create a new XML node for a CDATA section bound to document, with a given value.
Note that this does not insert the node into the document tree, to do so call appendChild.
This is represented as <![CDATA[ ... ]]> in XML.
| document | Containing document. |
| value | Node value, such as "Hello, world!". |
|
static |
Create a new XML node for a comment bound to document, with a given value.
Note that this does not insert the node into the document tree, to do so call appendChild.
This is represented as <!-- ... --> in XML.
| document | Containing document. |
| value | Node value, such as "Hello, world!". |
|
static |
Create a new XML node for text data bound to document, with a given value.
Note that this does not insert the node into the document tree, to do so call appendChild.
| document | Containing document. |
| value | Node value, such as "Hello, world!". |
|
static |
Create a new XML node for a document type declaration bound to document, with a given value.
Note that this does not insert the node into the document tree, to do so call appendChild.
This is represented as <!DOCTYPE ...> in XML.
| document | Containing document. |
| value | Node value, such as svg. |
|
staticprotected |
Create an XMLNode for the root node of a document.
This is called internally by donner::xml::XMLDocument.
|
static |
Create a new XML node for an element bound to document.
Note that this does not insert the node into the document tree, to do so call appendChild.
| document | Containing document. |
| tagName | Node tag name, such as "xml" or "svg". |
|
static |
Create an XML element node facade on an existing entity in document.
This is used by upper layers that create SVG entities programmatically and later need to insert them into an XML source-backed document. If handle already has a TreeComponent, its tag name must match tagName.
| document | Containing document. |
| handle | Existing entity to attach XML element identity to. |
| tagName | Node tag name, such as "xml" or "svg". |
|
staticprotected |
|
static |
Create a new XML node for a processing instruction bound to document, with a given target and value.
Note that this does not insert the node into the document tree, to do so call appendChild.
This is represented as <?php ... ?> in XML.
| document | Containing document. |
| target | Processing instruction target, such as "php". |
| value | Processing instruction value, such as "echo 'Hello, world!';". |
|
static |
Create a new XML node for an XML declaration bound to document.
Note that this does not insert the node into the document tree, to do so call appendChild.
This is represented as <?xml ... ?> in XML.
Contents of the declaration are accessible through the attribute getters/setters.
| document | Containing document. |
| std::optional< XMLNode > donner::xml::XMLNode::firstChild | ( | ) | const |
Get the first child of this element that is part of the XML document, if it exists.
The document tree also holds nodes the XML layer never created: content the renderer synthesizes while drawing a reference such as <use>, and elements created through the SVG DOM that have not been projected into the document yet. Those are not part of the authored XML document, so neither this accessor nor the other tree accessors ever return one.
std::nullopt if the element has no XML children. | std::optional< RcString > donner::xml::XMLNode::getAttribute | ( | const XMLQualifiedNameRef & | name | ) | const |
Get the value of an attribute, if it exists.
| name | Name of the attribute to get. |
std::nullopt if the attribute does not exist. | std::optional< SourceRange > donner::xml::XMLNode::getAttributeLocation | ( | std::string_view | xmlInput, |
| const XMLQualifiedNameRef & | name ) const |
Get the location of an attribute in the input string.
For example, for the following XML:
The SourceRange for the attr attribute should contain the substring attr="Hello, world!"
| xmlInput | Input string to get the attribute location in. |
| name | Name of the attribute to get the location for. |
std::nullopt if the attribute does not exist. | std::optional< XMLAttributeSourceLocation > donner::xml::XMLNode::getAttributeSourceLocation | ( | const XMLQualifiedNameRef & | name | ) | const |
Get resolved source metadata for an attribute.
| name | Name of the attribute to locate. |
std::nullopt if unavailable. | std::optional< SourceRange > donner::xml::XMLNode::getClosingTagLocation | ( | ) | const |
Get this node's closing tag/source suffix location.
For an element this is the closing tag, e.g. </text>. For text-like nodes this is the fixed source suffix, e.g. --> for comments.
std::nullopt if unavailable. Get the namespace URI of an attribute prefix, if it exists.
| prefix | Prefix of the attribute to get the namespace URI for. |
std::nullopt if the prefix does not exist. | std::optional< SourceRange > donner::xml::XMLNode::getNodeLocation | ( | ) | const |
Get the location of this node in the input string.
For example, for the following XML:
The SourceRange for the child element should contain the substring <child>Hello, world!</child>
std::nullopt if source locations are not available. | std::optional< SourceRange > donner::xml::XMLNode::getOpeningTagLocation | ( | ) | const |
Get this node's opening tag/source prefix location.
For an element this is the opening tag, e.g. <rect fill="red"> or <rect/>. For text-like nodes this is the fixed source prefix, e.g. <!-- for comments.
std::nullopt if unavailable. | std::optional< SourceRange > donner::xml::XMLNode::getValueLocation | ( | ) | const |
Get this node's value source location.
For a data node this is the raw PCDATA span. For comments, CDATA, doctype, and processing instructions this excludes the XML delimiters.
std::nullopt if unavailable. | bool donner::xml::XMLNode::hasAttribute | ( | const XMLQualifiedNameRef & | name | ) | const |
Returns true if the element has an attribute with the given name.
| name | Name of the attribute to check. |
| void donner::xml::XMLNode::insertBefore | ( | const XMLNode & | newNode, |
| std::optional< XMLNode > | referenceNode ) |
Insert newNode as a child, before referenceNode.
If referenceNode is std::nullopt, append the child.
If newNode is already in the tree, it is first removed from its parent. However, if inserting the child will create a cycle, the behavior is undefined.
| newNode | New node to insert. |
| referenceNode | A child of this node to insert newNode before, or std::nullopt. Must be a child of the current node. |
| std::optional< XMLNode > donner::xml::XMLNode::lastChild | ( | ) | const |
Get the last child of this element that is part of the XML document, if it exists.
See firstChild for which nodes are left out.
std::nullopt if the element has no XML children. | std::optional< XMLNode > donner::xml::XMLNode::nextSibling | ( | ) | const |
Get the next sibling of this element that is part of the XML document, if it exists.
See firstChild for which nodes are left out.
std::nullopt if the element has no next XML sibling. | std::optional< XMLNode > donner::xml::XMLNode::parentElement | ( | ) | const |
Get this element's parent, if it exists.
Reports nothing when this is the document root, when this node has not been inserted into the document tree, and when the enclosing node is not part of the authored XML document (see firstChild) - in that last case this reports nothing rather than skipping outward to the nearest enclosing authored node.
std::nullopt if there is no authored parent. | std::optional< XMLNode > donner::xml::XMLNode::previousSibling | ( | ) | const |
Get the previous sibling of this element that is part of the XML document, if it exists.
See firstChild for which nodes are left out.
std::nullopt if the element has no previous XML sibling. | void donner::xml::XMLNode::remove | ( | ) |
Remove this node from its parent, if it has one.
Has no effect if this has no parent.
| void donner::xml::XMLNode::removeAttribute | ( | const XMLQualifiedNameRef & | name | ) |
Remove an attribute and clear its source metadata.
| name | Name of the attribute to remove. |
| void donner::xml::XMLNode::removeChild | ( | const XMLNode & | child | ) |
Remove child from this node.
| child | Child to remove, must be a child of the current node. |
Replace oldChild with newChild in the tree, removing oldChild and inserting newChild in its place.
If newChild is already in the tree, it is first removed from its parent. However, if inserting the child will create a cycle, the behavior is undefined.
| newChild | New child to insert. |
| oldChild | Old child to remove, must be a child of the current node. |
| RcString donner::xml::XMLNode::serializeToString | ( | int | indentLevel = 0, |
| bool | prettyPrint = true ) const |
Serialize this node to an XML string.
Produces a normalized XML representation suitable for programmatically-created nodes (e.g. nodes created by canvas tools that have no original source location). This function does not preserve original author whitespace.
Serialization rules per node type:
Attribute values are escaped via donner::xml::EscapeAttributeValue. If an attribute value cannot be represented in well-formed XML (e.g. it contains NUL bytes), it is omitted from the output. Data text that cannot be represented in well-formed XML is written unescaped.
When prettyPrint is set and an element has at least one element child, every child, including text, is written on its own line indented by indentLevel + 1 levels (2 spaces per level). An element whose children are all text-like is written inline.
| indentLevel | Current indentation depth; each level adds 2 spaces of leading whitespace. |
| prettyPrint | Whether to insert indentation whitespace between child elements. |
| void donner::xml::XMLNode::setAttribute | ( | const XMLQualifiedNameRef & | name, |
| std::string_view | value ) |
Set the value of an XML attribute, adding the attribute if it does not exist.
This API only stores the name and value strings, and does not parse them. To parse presentation attributes, use the upper-layer API: donner::svg::SVGElement::setAttribute.
| name | Name of the attribute to set. |
| value | New value to set. |
| void donner::xml::XMLNode::setAttributeSourceLocation | ( | const XMLQualifiedNameRef & | name, |
| SourceRange | fullRange, | ||
| SourceRange | valueRange, | ||
| char | quote ) |
Store source metadata for an attribute using the document source store.
If the node is not source-backed, any existing attribute metadata for name is cleared.
| name | Name of the attribute to update. |
| fullRange | Full serialized attribute range. |
| valueRange | Unquoted value range. |
| quote | Quote delimiter used for the value. |
| void donner::xml::XMLNode::setClosingTagLocation | ( | SourceRange | range | ) |
Store this node's closing tag/source suffix location.
| range | Closing tag/source suffix range. |
| void donner::xml::XMLNode::setOpeningTagLocation | ( | SourceRange | range | ) |
Store this node's opening tag/source prefix location.
| range | Opening tag/source prefix range. |
| void donner::xml::XMLNode::setSourceEndOffset | ( | FileOffset | offset | ) |
Set the source offset of where this node ends in the XML document source.
| offset | Offset in the source document, in characters from the start. |
| void donner::xml::XMLNode::setSourceStartOffset | ( | FileOffset | offset | ) |
Set the source offset of where this node starts in the XML document source.
| offset | Offset in the source document, in characters from the start. |
| void donner::xml::XMLNode::setValueLocation | ( | SourceRange | range | ) |
Store this node's value source location.
| range | Value source range. |
|
inlineprotected |
Convert an Entity to an EntityHandle, for advanced use.
| entity | Entity to convert. |
|
static |
Try to cast to an XMLNode from a raw Entity.
This is a checked cast, and will return std::nullopt if the entity is not an XML node.
| entity | Entity to cast. |
| std::optional< RcString > donner::xml::XMLNode::value | ( | ) | const |
Get the value of this node, which depends on the node type.
For nodes without a value, this will return std::nullopt.