Chapter 62. Modifying XML documents using writer locks

Index

Creator factories
Creating new XML elements and attributes
Creating other kinds of XML nodes, and other writer lock methods
Removing XML document nodes
An example of creating an XML document
#include <x/xml/writelock>

auto doc=x::xml::doc::create();

x::xml::doc::base::writelock wlock=doc->writelock();

A writer lock blocks all other reader and writer locks. It blocks the creation of all other locks. If any other lock exists, writelock() blocks until all other locks go out of scope and gets destroyed.

x::xml::writelock is a reference to a reference-counted object. Copying x::xml::doc::base::writelock variables does not create new writer locks, only more references to the same writer lock get created. The writer lock object is a subclass of a reader lock, and implements all reader lock methods, except for clone(). Only one writer lock can exist at a time. Invoking a writer lock's clone() method throws an exception.

Creator factories

Creating new elements in an XML document is a two-step process:

  1. Invoke either the writer lock's create_child(), create_next_sibling(), or the create_previous_sibling() method.

  2. These methods return a x::xml::createnode, or a creator factory, which is a reference to a reference-counted object with several methods that create a new element, comment, a processing instruction, or some other part of an XML document. create_child()'s methods add the new element as a child element of the current node. Invoking create_next_sibling()'s or create_previous_sibling()'s method adds the new element as the corresponding sibling element of the writer lock's current node.

Before invoking a creator factory's method, the writer lock should be positioned, using the methods that it inherits from the reader lock, to the appropriate existing element in the XML document. Afterwards, invoking one of creator factory's methods creates a new XML node, and installs it with respect to the writer lock's current node. As a special case, a new writer lock in a new, empty document, is not positioned on any existing node. If a writer lock is not positioned on any node, its create_child()'s methods installs the document's root node.

In all cases, after creating and installing a new XML node, the writer lock is repositioned so that its current node is the new XML node. Invoking another (or the same) creator factory method creates another new XML node. The second new XML node gets installed again, by the creator factory, with respect to the first XML node. So, for example, using create_child()'s creator factory installs the first new node as a child node of the original XML parent node, and invoking one of creator factory's methods again installs the second new node as a child node of the first new node, since the first new node became the writer lock's current node.

Note

The creator factory holds a reference on the writer lock, until the last reference to the creator factory goes out of scope, and it gets destroyed.

The creator factory is not bound to any particular part of the XML document, it is bound to a writer lock (on which it holds an internal reference), and the writer lock is positioned on some existing element of the XML document. The writer lock uses the same methods as a reader lock (it inherits them), to change its current position. It is not necessary to destroy a creator factory, then recreate it after reposition the writer lock. If it's the same creator factory type (create_child(), create_next_sibling(), or create_previous_sibling()), it's quite usable after repositioning the writer lock, and will continue to perform its duties, with respect to the writer lock's new position.

wlock->create_child()->element({"p"})
     ->create_next_sibling()->element({"p"})
     ->parent()->element({"p"});

This example calls a writer lock's create_child() factory. The writer lock is presumed to be already positioned on an existing XML element node. The creator factory's element() creates a new <p> node, and the creator factory installs this as a new child element, then repositions the writer lock to the new element.

element() returns a reference to the same creator factory, and at this point, invoking element() would create a second XML element, and install it as <p>'s child element, because it's now the writer lock's current element.

For convenience, each creator factory also implements its origin writer lock's create_child(), create_next_sibling(), and create_previous_sibling() methods, that return the other types of creator factories. This allows a single statement to create new XML nodes in different directions. The above example switches to the create_next_sibling() creator factory and installs another <p> element as its sibling. The net effect is the creation of two <p> elements from the parent node.

For convenience, each creator factory also implements parent() by repositioning the writer lock to its current node's parent node. After creating these two new <p> child elements of of the parent node, the writer lock gets positioned on the second child element. parent() repositions the writer lock to the original parent node. The creator factory remains unchanged, it's still create_next_sibling(), and a third call to element() creates a sibling element of the original parent node.