From f9a2dec792d9a52e1b9004793cfca9b0a463049a Mon Sep 17 00:00:00 2001 From: "arseny.kapoulkine" Date: Sun, 11 Jul 2010 16:27:23 +0000 Subject: docs: Added generated HTML documentation git-svn-id: http://pugixml.googlecode.com/svn/trunk@596 99668b35-9821-0410-8761-19e4c4f06640 --- docs/manual/modify.html | 541 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 541 insertions(+) create mode 100644 docs/manual/modify.html (limited to 'docs/manual/modify.html') diff --git a/docs/manual/modify.html b/docs/manual/modify.html new file mode 100644 index 0000000..f00e657 --- /dev/null +++ b/docs/manual/modify.html @@ -0,0 +1,541 @@ + + + +Modifying document data + + + + + + + + + + + +
pugixml 0.9 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
+PrevUpHomeNext +
+
+
+ + +

+ The document in pugixml is fully mutable: you can completely change the document + structure and modify the data of nodes/attributes. This section provides documentation + for the relevant functions. All functions take care of memory management and + structural integrity themselves, so they always result in structurally valid + tree - however, it is possible to create an invalid XML tree (for example, + by adding two attributes with the same name or by setting attribute/node name + to empty/invalid string). Tree modification is optimized for performance and + for memory consumption, so if you have enough memory you can create documents + from scratch with pugixml and later save them to file/stream instead of relying + on error-prone manual text writing and without too much overhead. +

+

+ All member functions that change node/attribute data or structure are non-constant + and thus can not be called on constant handles. However, you can easily convert + constant handle to non-constant one by simple assignment: void + foo(const pugi::xml_node& n) + { pugi::xml_node nc = n; }, so const-correctness + here mainly provides additional documentation. +

+
+ +

+ As discussed before, nodes can have name and value, both of which are strings. + Depending on node type, name or value may be absent. node_document + nodes do not have name or value, node_element + and node_declaration nodes + always have a name but never have a value, node_pcdata, + node_cdata and node_comment nodes never have a name but + always have a value (it may be empty though), node_pi + nodes always have a name and a value (again, value may be empty). In order + to set node's name or value, you can use the following functions: +

+
bool xml_node::set_name(const char_t* rhs);
+bool xml_node::set_value(const char_t* rhs);
+
+

+ Both functions try to set the name/value to the specified string, and return + the operation result. The operation fails if the node can not have name or + value (for instance, when trying to call set_name + on a node_pcdata node), if + the node handle is null, or if there is insufficient memory to handle the + request. The provided string is copied into document managed memory and can + be destroyed after the function returns (for example, you can safely pass + stack-allocated buffers to these functions). The name/value content is not + verified, so take care to use only valid XML names, or the document may become + malformed. +

+

+ There is no equivalent of child_value + function for modifying text children of the node. +

+

+ This is an example of setting node name and value (samples/modify_base.cpp): +

+

+ +

+
pugi::xml_node node = doc.child("node");
+
+// change node name
+std::cout << node.set_name("notnode");
+std::cout << ", new node name: " << node.name() << std::endl;
+
+// change comment text
+std::cout << doc.last_child().set_value("useless comment");
+std::cout << ", new comment text: " << doc.last_child().value() << std::endl;
+
+// we can't change value of the element or name of the comment
+std::cout << node.set_value("1") << ", " << doc.last_child().set_name("2") << std::endl;
+
+

+

+
+
+ +

+ All attributes have name and value, both of which are strings (value may + be empty). You can set them with the following functions: +

+
bool xml_attribute::set_name(const char_t* rhs);
+bool xml_attribute::set_value(const char_t* rhs);
+
+

+ Both functions try to set the name/value to the specified string, and return + the operation result. The operation fails if the attribute handle is null, + or if there is insufficient memory to handle the request. The provided string + is copied into document managed memory and can be destroyed after the function + returns (for example, you can safely pass stack-allocated buffers to these + functions). The name/value content is not verified, so take care to use only + valid XML names, or the document may become malformed. +

+

+ In addition to string functions, several functions are provided for handling + attributes with numbers and booleans as values: +

+
bool xml_attribute::set_value(int rhs);
+bool xml_attribute::set_value(unsigned int rhs);
+bool xml_attribute::set_value(double rhs);
+bool xml_attribute::set_value(bool rhs);
+
+

+ The above functions convert the argument to string and then call the base + set_value function. Integers + are converted to a decimal form, floating-point numbers are converted to + either decimal or scientific form, depending on the number magnitude, boolean + values are converted to either "true" + or "false". +

+
+ + + + + +
[Caution]Caution

+ Number conversion functions depend on current C locale as set with setlocale, so may generate unexpected + results if the locale is different from "C". +

+
+ + + + + +
[Note]Note

+ There are no portable 64-bit types in C++, so there is no corresponding + set_value function. If + your platform has a 64-bit integer, you can easily write such a function + yourself. +

+

+ For convenience, all set_value + functions have the corresponding assignment operators: +

+
xml_attribute& xml_attribute::operator=(const char_t* rhs);
+xml_attribute& xml_attribute::operator=(int rhs);
+xml_attribute& xml_attribute::operator=(unsigned int rhs);
+xml_attribute& xml_attribute::operator=(double rhs);
+xml_attribute& xml_attribute::operator=(bool rhs);
+
+

+ These operators simply call the right set_value + function and return the attribute they're called on; the return value of + set_value is ignored, so + errors are not detected. +

+

+ This is an example of setting attribute name and value (samples/modify_base.cpp): +

+

+ +

+
pugi::xml_attribute attr = node.attribute("id");
+
+// change attribute name/value
+std::cout << attr.set_name("key") << ", " << attr.set_value("345");
+std::cout << ", new attribute: " << attr.name() << "=" << attr.value() << std::endl;
+
+// we can use numbers or booleans
+attr.set_value(1.234);
+std::cout << "new attribute value: " << attr.value() << std::endl;
+
+// we can also use assignment operators for more concise code
+attr = true;
+std::cout << "final attribute value: " << attr.value() << std::endl;
+
+

+

+
+
+ +

+ Nodes and attributes do not exist outside of document tree, so you can't + create them without adding them to some document. A node or attribute can + be created at the end of node/attribute list or before/after some other node: +

+
xml_attribute xml_node::append_attribute(const char_t* name);
+xml_attribute xml_node::insert_attribute_after(const char_t* name, const xml_attribute& attr);
+xml_attribute xml_node::insert_attribute_before(const char_t* name, const xml_attribute& attr);
+
+xml_node xml_node::append_child(xml_node_type type = node_element);
+xml_node xml_node::insert_child_after(xml_node_type type, const xml_node& node);
+xml_node xml_node::insert_child_before(xml_node_type type, const xml_node& node);
+
+

+ append_attribute and append_child create a new node/attribute + at the end of the corresponding list of the node the method is called on; + insert_attribute_after, + insert_attribute_before, + insert_child_after and insert_attribute_before add the node/attribute + before or after specified node/attribute. +

+

+ Attribute functions create an attribute with the specified name; you can + specify the empty name and change the name later if you want to. Node functions + create the node with the specified type; since node type can't be changed, + you have to know the desired type beforehand. Also note that not all types + can be added as children; see below for clarification. +

+

+ All functions return the handle to newly created object on success, and null + handle on failure. There are several reasons for failure: +

+
    +
  • + Adding fails if the target node is null; +
  • +
  • + Only node_element nodes + can contain attributes, so attribute adding fails if node is not an element; +
  • +
  • + Only node_document and + node_element nodes can + contain children, so child node adding fails if target node is not an + element or a document; +
  • +
  • + node_document and node_null nodes can not be inserted + as children, so passing node_document + or node_null value as + type results in operation failure; +
  • +
  • + node_declaration nodes + can only be added as children of the document node; attempt to insert + declaration node as a child of an element node fails; +
  • +
  • + Adding node/attribute results in memory allocation, which may fail; +
  • +
  • + Insertion functions fail if the specified node or attribute is not in + the target node's children/attribute list. +
  • +
+

+ Even if the operation fails, the document remains in consistent state, but + the requested node/attribute is not added. +

+
+ + + + + +
[Caution]Caution

+ attribute() and child() functions do not add attributes or nodes to the + tree, so code like node.attribute("id") = 123; will not do anything if node does not have an attribute with + name "id". Make sure + you're operating with existing attributes/nodes by adding them if necessary. +

+

+ This is an example of adding new attributes/nodes to the document (samples/modify_add.cpp): +

+

+ +

+
// add node with some name
+pugi::xml_node node = doc.append_child();
+node.set_name("node");
+
+// add description node with text child
+pugi::xml_node descr = node.append_child();
+descr.set_name("description");
+descr.append_child(pugi::node_pcdata).set_value("Simple node");
+
+// add param node before the description
+pugi::xml_node param = node.insert_child_before(pugi::node_element, descr);
+param.set_name("param");
+
+// add attributes to param node
+param.append_attribute("name") = "version";
+param.append_attribute("value") = 1.1;
+param.insert_attribute_after("type", param.attribute("name")) = "float";
+
+

+

+
+
+ +

+ If you do not want your document to contain some node or attribute, you can + remove it with one of the following functions: +

+
bool xml_node::remove_attribute(const xml_attribute& a);
+bool xml_node::remove_child(const xml_node& n);
+
+

+ remove_attribute removes + the attribute from the attribute list of the node, and returns the operation + result. remove_child removes + the child node with the entire subtree (including all descendant nodes and + attributes) from the document, and returns the operation result. Removing + fails if one of the following is true: +

+
    +
  • + The node the function is called on is null; +
  • +
  • + The attribute/node to be removed is null; +
  • +
  • + The attribute/node to be removed is not in the node's attribute/child + list. +
  • +
+

+ Removing the attribute or node invalidates all handles to the same underlying + object, and also invalidates all iterators pointing to the same object. Removing + node also invalidates all past-the-end iterators to its attribute or child + node list. Be careful to ensure that all such handles and iterators either + do not exist or are not used after the attribute/node is removed. +

+

+ If you want to remove the attribute or child node by its name, two additional + helper functions are available: +

+
bool xml_node::remove_attribute(const char_t* name);
+bool xml_node::remove_child(const char_t* name);
+
+

+ These functions look for the first attribute or child with the specified + name, and then remove it, returning the result. If there is no attribute + or child with such name, the function returns false; + if there are two nodes with the given name, only the first node is deleted. + If you want to delete all nodes with the specified name, you can use code + like this: while (node.remove_child("tool")) ;. +

+

+ This is an example of removing attributes/nodes from the document (samples/modify_remove.cpp): +

+

+ +

+
// remove description node with the whole subtree
+pugi::xml_node node = doc.child("node");
+node.remove_child("description");
+
+// remove id attribute
+pugi::xml_node param = node.child("param");
+param.remove_attribute("value");
+
+// we can also remove nodes/attributes by handles
+pugi::xml_attribute id = param.attribute("name");
+param.remove_attribute(id);
+
+

+

+
+
+ +

+ With the help of previously described functions, it is possible to create + trees with any contents and structure, including cloning the existing data. + However since this is an often needed operation, pugixml provides built-in + node/attribute cloning facilities. Since nodes and attributes do not exist + outside of document tree, you can't create a standalone copy - you have to + immediately insert it somewhere in the tree. For this, you can use one of + the following functions: +

+
xml_attribute xml_node::append_copy(const xml_attribute& proto);
+xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr);
+xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr);
+xml_node xml_node::append_copy(const xml_node& proto);
+xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node);
+xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node);
+
+

+ These functions mirror the structure of append_child, + insert_child_before and related + functions - they take the handle to the prototype object, which is to be + cloned, insert a new attribute/node at the appropriate place, and then copy + the attribute data or the whole node subtree to the new object. The functions + return the handle to the resulting duplicate object, or null handle on failure. +

+

+ The attribute is copied along with the name and value; the node is copied + along with its type, name and value; additionally attribute list and all + children are recursively cloned, resulting in the deep subtree clone. The + prototype object can be a part of the same document, or a part of any other + document. +

+

+ The failure conditions resemble those of append_child, + insert_child_before and related + functions, consult their documentation + for more information. There are additional caveats specific to cloning + functions: +

+
    +
  • + Cloning null handles results in operation failure; +
  • +
  • + Node cloning starts with insertion of the node of the same type as that + of the prototype; for this reason, cloning functions can not be directly + used to clone entire documents, since node_document + is not a valid insertion type. The example below provides a workaround. +
  • +
  • + It is possible to copy a subtree as a child of some node inside this + subtree, i.e. node.append_copy(node.parent().parent());. + This is a valid operation, and it results in a clone of the subtree in + the state before cloning started, i.e. no infinite recursion takes place. +
  • +
+

+ This is an example with one possible implementation of include tags in XML + (samples/include.cpp). It illustrates + node cloning and usage of other document modification functions: +

+

+ +

+
bool load_preprocess(pugi::xml_document& doc, const char* path);
+
+bool preprocess(pugi::xml_node node)
+{
+    for (pugi::xml_node child = node.first_child(); child; )
+    {
+        if (child.type() == pugi::node_pi && strcmp(child.name(), "include") == 0)
+        {
+            pugi::xml_node include = child;
+
+            // load new preprocessed document (note: ideally this should handle relative paths)
+            const char* path = include.value();
+
+            pugi::xml_document doc;
+            if (!load_preprocess(doc, path)) return false;
+
+            // insert the comment marker above include directive
+            node.insert_child_before(pugi::node_comment, include).set_value(path);
+
+            // copy the document above the include directive (this retains the original order!)
+            for (pugi::xml_node ic = doc.first_child(); ic; ic = ic.next_sibling())
+            {
+                node.insert_copy_before(ic, include);
+            }
+
+            // remove the include node and move to the next child
+            child = child.next_sibling();
+
+            node.remove_child(include);
+        }
+        else
+        {
+            if (!preprocess(child)) return false;
+
+            child = child.next_sibling();
+        }
+    }
+
+    return true;
+}
+
+bool load_preprocess(pugi::xml_document& doc, const char* path)
+{
+    pugi::xml_parse_result result = doc.load_file(path, pugi::parse_default | pugi::parse_pi); // for <?include?>
+    
+    return result ? preprocess(doc) : false;
+}
+
+

+

+
+
+ + + +
+
+ + + +
pugixml 0.9 manual | + Overview | + Installation | + Document: + Object model · Loading · Accessing · Modifying · Saving | + XPath | + API Reference | + Table of Contents +
+PrevUpHomeNext +
+ + -- cgit v1.2.3