From 28feddf013746d33c77cd29eb7e275300d664e19 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Sun, 16 Nov 2014 20:27:01 -0800 Subject: docs: Replace Subversion links with Git --- docs/manual.qbk | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/docs/manual.qbk b/docs/manual.qbk index 833962d..617a971 100644 --- a/docs/manual.qbk +++ b/docs/manual.qbk @@ -99,7 +99,7 @@ pugixml is Copyright (C) 2006-2014 Arseny Kapoulkine. [section:getting Getting pugixml] -pugixml is distributed in source form. You can either download a source distribution or checkout the Subversion repository. +pugixml is distributed in source form. You can either download a source distribution or clone the Git repository. [section:source Source distributions] @@ -112,33 +112,35 @@ You can download the latest source distribution via one of the following links: The distribution contains library source, documentation (the manual you're reading now and the quick start guide) and some code examples. After downloading the distribution, install pugixml by extracting all files from the compressed archive. The files have different line endings depending on the archive format - [file .zip] archive has Windows line endings, [file .tar.gz] archive has Unix line endings. Otherwise the files in both archives are identical. -If you need an older version, you can download it from the [@http://code.google.com/p/pugixml/downloads/list version archive]. +If you need an older version, you can download it from the [@https://github.com/zeux/pugixml/releases version archive]. [endsect] [/source] -[section:subversion Subversion repository] +[section:git Git repository] -The Subversion repository is located at [@http://pugixml.googlecode.com/svn/]. There is a Subversion tag "release-{version}" for each version; also there is the "latest" tag, which always points to the latest stable release. +The Git repository is located at [@https://github.com/zeux/pugixml/]. There is a Git tag "v{version}" for each version; also there is the "latest" tag, which always points to the latest stable release. For example, to checkout the current version, you can use this command: -[pre svn checkout http://pugixml.googlecode.com/svn/tags/release-1.4 pugixml] - -To checkout the latest version, you can use this command: - -[pre svn checkout http://pugixml.googlecode.com/svn/tags/latest pugixml] +[pre +git clone https://github.com/zeux/pugixml +cd pugixml +git checkout v1.4 +] The repository contains library source, documentation, code examples and full unit test suite. -Use latest version tag if you want to automatically get new versions via =svn update=. Use other tags if you want to switch to new versions only explicitly (for example, using =svn switch= command). Also please note that Subversion trunk contains the work-in-progress version of the code; while this means that you can get new features and bug fixes from trunk without waiting for a new release, this also means that occasionally the code can be broken in some configurations. +Use latest version tag if you want to automatically get new versions. Use other tags if you want to switch to new versions only explicitly. Also please note that the master branch contains the work-in-progress version of the code; while this means that you can get new features and bug fixes from master without waiting for a new release, this also means that occasionally the code can be broken in some configurations. -[endsect] [/subversion] +[endsect] [/git] -[section:git Git repository] +[section:subversion Subversion repository] -The Subversion repository is mirrored by a Git repository at [@https://github.com/zeux/pugixml]. The mirror is frequently updated and has the same structure in terms of tags and contents as Subversion repository. +You can access the Git repository via Subversion using [@https://github.com/zeux/pugixml] URL. For example, to checkout the current version, you can use this command: -[endsect] [/git] +[pre svn checkout https://github.com/zeux/pugixml/tags/v1.4 pugixml] + +[endsect] [/subversion] [endsect] [/getting] -- cgit v1.2.3 From 79ed320f894c406dd3548e7d34cadd07fa82fb53 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Mon, 17 Nov 2014 08:35:34 -0800 Subject: tests: Don't use /dev/tty The behavior on OSX is different - we don't get a I/O error so the test is useless. --- tests/test_document.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/test_document.cpp b/tests/test_document.cpp index 2774a07..2cc39a6 100644 --- a/tests/test_document.cpp +++ b/tests/test_document.cpp @@ -301,10 +301,6 @@ TEST(document_load_file_error) CHECK(doc.load_file("filedoesnotexist").status == status_file_not_found); -#ifndef _WIN32 - CHECK(doc.load_file("/dev/tty").status == status_io_error); -#endif - test_runner::_memory_fail_threshold = 1; CHECK(doc.load_file("tests/data/small.xml").status == status_out_of_memory); } -- cgit v1.2.3 From e9956ae3a6593efc6f8cb344a00432ece51d1574 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Mon, 17 Nov 2014 19:52:23 -0800 Subject: Rename xml_document::load to load_string This should completely eliminate the confusion between load and load_file. Of course, for compatibility reasons we have to preserve the old variant - it will be deprecated in a future version and subsequently removed. --- docs/manual.qbk | 4 +- docs/samples/custom_memory_management.cpp | 2 +- docs/samples/load_error_handling.cpp | 2 +- docs/samples/load_memory.cpp | 2 +- docs/samples/load_options.cpp | 8 +- docs/samples/modify_base.cpp | 2 +- docs/samples/modify_remove.cpp | 2 +- docs/samples/save_custom_writer.cpp | 2 +- docs/samples/save_declaration.cpp | 2 +- docs/samples/save_file.cpp | 2 +- docs/samples/save_options.cpp | 2 +- docs/samples/save_stream.cpp | 2 +- docs/samples/save_subtree.cpp | 2 +- docs/samples/text.cpp | 2 +- src/pugixml.cpp | 7 +- src/pugixml.hpp | 5 +- tests/test.hpp | 2 +- tests/test_document.cpp | 23 ++- tests/test_dom_modify.cpp | 4 +- tests/test_memory.cpp | 2 +- tests/test_parse.cpp | 328 +++++++++++++++--------------- tests/test_parse_doctype.cpp | 20 +- tests/test_write.cpp | 2 +- tests/test_xpath.cpp | 6 +- 24 files changed, 225 insertions(+), 210 deletions(-) diff --git a/docs/manual.qbk b/docs/manual.qbk index 617a971..6d7f4e1 100644 --- a/docs/manual.qbk +++ b/docs/manual.qbk @@ -602,7 +602,7 @@ The best way from the performance/memory point of view is to load document using [#xml_document::load_string] There is also a simple helper function for cases when you want to load the XML document from null-terminated character string: - xml_parse_result xml_document::load(const char_t* contents, unsigned int options = parse_default); + xml_parse_result xml_document::load_string(const char_t* contents, unsigned int options = parse_default); It is equivalent to calling `load_buffer` with `size` being either `strlen(contents)` or `wcslen(contents) * sizeof(wchar_t)`, depending on the character type. This function assumes native encoding for input data, so it does not do any encoding conversion. In general, this function is fine for loading small documents from string literals, but has more overhead and less functionality than the buffer loading functions. @@ -2503,7 +2503,7 @@ Classes: * `xml_parse_result `[link xml_document::load_stream load]`(std::wistream& stream, unsigned int options = parse_default);` [lbr] - * `xml_parse_result `[link xml_document::load_string load]`(const char_t* contents, unsigned int options = parse_default);` + * `xml_parse_result `[link xml_document::load_string load_string]`(const char_t* contents, unsigned int options = parse_default);` [lbr] * `xml_parse_result `[link xml_document::load_file load_file]`(const char* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);` diff --git a/docs/samples/custom_memory_management.cpp b/docs/samples/custom_memory_management.cpp index 92ccb71..f11d27e 100644 --- a/docs/samples/custom_memory_management.cpp +++ b/docs/samples/custom_memory_management.cpp @@ -21,7 +21,7 @@ int main() //] pugi::xml_document doc; - doc.load(""); + doc.load_string(""); } // vim:et diff --git a/docs/samples/load_error_handling.cpp b/docs/samples/load_error_handling.cpp index 18dd331..8dceb99 100644 --- a/docs/samples/load_error_handling.cpp +++ b/docs/samples/load_error_handling.cpp @@ -6,7 +6,7 @@ void check_xml(const char* source) { //[code_load_error_handling pugi::xml_document doc; - pugi::xml_parse_result result = doc.load(source); + pugi::xml_parse_result result = doc.load_string(source); if (result) std::cout << "XML [" << source << "] parsed without errors, attr value: [" << doc.child("node").attribute("attr").value() << "]\n\n"; diff --git a/docs/samples/load_memory.cpp b/docs/samples/load_memory.cpp index 1185944..490f7e4 100644 --- a/docs/samples/load_memory.cpp +++ b/docs/samples/load_memory.cpp @@ -55,7 +55,7 @@ int main() { //[code_load_memory_string // You can use load to load document from null-terminated strings, for example literals: - pugi::xml_parse_result result = doc.load("0 0 1 1"); + pugi::xml_parse_result result = doc.load_string("0 0 1 1"); //] std::cout << "Load result: " << result.description() << ", mesh name: " << doc.child("mesh").attribute("name").value() << std::endl; diff --git a/docs/samples/load_options.cpp b/docs/samples/load_options.cpp index 04b4b46..2589348 100644 --- a/docs/samples/load_options.cpp +++ b/docs/samples/load_options.cpp @@ -10,19 +10,19 @@ int main() const char* source = "<"; // Parsing with default options; note that comment node is not added to the tree, and entity reference < is expanded - doc.load(source); + doc.load_string(source); std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n"; // Parsing with additional parse_comments option; comment node is now added to the tree - doc.load(source, pugi::parse_default | pugi::parse_comments); + doc.load_string(source, pugi::parse_default | pugi::parse_comments); std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n"; // Parsing with additional parse_comments option and without the (default) parse_escapes option; < is not expanded - doc.load(source, (pugi::parse_default | pugi::parse_comments) & ~pugi::parse_escapes); + doc.load_string(source, (pugi::parse_default | pugi::parse_comments) & ~pugi::parse_escapes); std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n"; // Parsing with minimal option mask; comment node is not added to the tree, and < is not expanded - doc.load(source, pugi::parse_minimal); + doc.load_string(source, pugi::parse_minimal); std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n"; //] } diff --git a/docs/samples/modify_base.cpp b/docs/samples/modify_base.cpp index 7d0959a..bd63708 100644 --- a/docs/samples/modify_base.cpp +++ b/docs/samples/modify_base.cpp @@ -6,7 +6,7 @@ int main() { pugi::xml_document doc; - if (!doc.load("text", pugi::parse_default | pugi::parse_comments)) return -1; + if (!doc.load_string("text", pugi::parse_default | pugi::parse_comments)) return -1; //[code_modify_base_node pugi::xml_node node = doc.child("node"); diff --git a/docs/samples/modify_remove.cpp b/docs/samples/modify_remove.cpp index 28c2f6b..53020e1 100644 --- a/docs/samples/modify_remove.cpp +++ b/docs/samples/modify_remove.cpp @@ -5,7 +5,7 @@ int main() { pugi::xml_document doc; - if (!doc.load("Simple node")) return -1; + if (!doc.load_string("Simple node")) return -1; //[code_modify_remove // remove description node with the whole subtree diff --git a/docs/samples/save_custom_writer.cpp b/docs/samples/save_custom_writer.cpp index 6ea4300..9e9ee34 100644 --- a/docs/samples/save_custom_writer.cpp +++ b/docs/samples/save_custom_writer.cpp @@ -94,7 +94,7 @@ int main() { // get a test document pugi::xml_document doc; - doc.load("hey"); + doc.load_string("hey"); // get contents as std::string (single pass) std::cout << "contents: [" << node_to_string(doc) << "]\n"; diff --git a/docs/samples/save_declaration.cpp b/docs/samples/save_declaration.cpp index 6c82061..a45831f 100644 --- a/docs/samples/save_declaration.cpp +++ b/docs/samples/save_declaration.cpp @@ -7,7 +7,7 @@ int main() //[code_save_declaration // get a test document pugi::xml_document doc; - doc.load("hey"); + doc.load_string("hey"); // add a custom declaration node pugi::xml_node decl = doc.prepend_child(pugi::node_declaration); diff --git a/docs/samples/save_file.cpp b/docs/samples/save_file.cpp index 30c1aa1..21413a2 100644 --- a/docs/samples/save_file.cpp +++ b/docs/samples/save_file.cpp @@ -6,7 +6,7 @@ int main() { // get a test document pugi::xml_document doc; - doc.load("hey"); + doc.load_string("hey"); //[code_save_file // save document to file diff --git a/docs/samples/save_options.cpp b/docs/samples/save_options.cpp index 6a49f66..82abdcd 100644 --- a/docs/samples/save_options.cpp +++ b/docs/samples/save_options.cpp @@ -7,7 +7,7 @@ int main() //[code_save_options // get a test document pugi::xml_document doc; - doc.load("hey"); + doc.load_string("hey"); // default options; prints // diff --git a/docs/samples/save_stream.cpp b/docs/samples/save_stream.cpp index d01965d..eba1863 100644 --- a/docs/samples/save_stream.cpp +++ b/docs/samples/save_stream.cpp @@ -6,7 +6,7 @@ int main() { // get a test document pugi::xml_document doc; - doc.load("hey"); + doc.load_string("hey"); //[code_save_stream // save document to standard output diff --git a/docs/samples/save_subtree.cpp b/docs/samples/save_subtree.cpp index 0091b3d..a94e10a 100644 --- a/docs/samples/save_subtree.cpp +++ b/docs/samples/save_subtree.cpp @@ -7,7 +7,7 @@ int main() //[code_save_subtree // get a test document pugi::xml_document doc; - doc.load("hey"); + doc.load_string("hey"); // print document to standard output (prints hey) doc.save(std::cout, "", pugi::format_raw); diff --git a/docs/samples/text.cpp b/docs/samples/text.cpp index 9b1cf69..a0d591b 100644 --- a/docs/samples/text.cpp +++ b/docs/samples/text.cpp @@ -7,7 +7,7 @@ int main() pugi::xml_document doc; // get a test document - doc.load("test1.1yes"); + doc.load_string("test1.1yes"); pugi::xml_node project = doc.child("project"); diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 884184c..852ccb9 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -5995,7 +5995,7 @@ namespace pugi } #endif - PUGI__FN xml_parse_result xml_document::load(const char_t* contents, unsigned int options) + PUGI__FN xml_parse_result xml_document::load_string(const char_t* contents, unsigned int options) { // Force native encoding (skip autodetection) #ifdef PUGIXML_WCHAR_MODE @@ -6007,6 +6007,11 @@ namespace pugi return load_buffer(contents, impl::strlength(contents) * sizeof(char_t), options, encoding); } + PUGI__FN xml_parse_result xml_document::load(const char_t* contents, unsigned int options) + { + return load_string(contents, options); + } + PUGI__FN xml_parse_result xml_document::load_file(const char* path_, unsigned int options, xml_encoding encoding) { reset(); diff --git a/src/pugixml.hpp b/src/pugixml.hpp index e252e16..7f52975 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -959,9 +959,12 @@ namespace pugi xml_parse_result load(std::basic_istream >& stream, unsigned int options = parse_default); #endif - // Load document from zero-terminated string. No encoding conversions are applied. + // (deprecated: use load_string instead) Load document from zero-terminated string. No encoding conversions are applied. xml_parse_result load(const char_t* contents, unsigned int options = parse_default); + // Load document from zero-terminated string. No encoding conversions are applied. + xml_parse_result load_string(const char_t* contents, unsigned int options = parse_default); + // Load document from file xml_parse_result load_file(const char* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); xml_parse_result load_file(const wchar_t* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto); diff --git a/tests/test.hpp b/tests/test.hpp index 509b0cd..4222638 100644 --- a/tests/test.hpp +++ b/tests/test.hpp @@ -95,7 +95,7 @@ struct dummy_fixture {}; \ test_fixture_##name() \ { \ - CHECK(doc.load(PUGIXML_TEXT(xml), flags)); \ + CHECK(doc.load_string(PUGIXML_TEXT(xml), flags)); \ } \ \ private: \ diff --git a/tests/test_document.cpp b/tests/test_document.cpp index 2cc39a6..4228602 100644 --- a/tests/test_document.cpp +++ b/tests/test_document.cpp @@ -158,7 +158,7 @@ TEST(document_load_stream_exceptions) TEST(document_load_stream_error_previous) { pugi::xml_document doc; - CHECK(doc.load(STR(""))); + CHECK(doc.load_string(STR(""))); CHECK(doc.first_child()); std::ifstream fs1("filedoesnotexist"); @@ -169,7 +169,7 @@ TEST(document_load_stream_error_previous) TEST(document_load_stream_wide_error_previous) { pugi::xml_document doc; - CHECK(doc.load(STR(""))); + CHECK(doc.load_string(STR(""))); CHECK(doc.first_child()); std::basic_ifstream fs1("filedoesnotexist"); @@ -261,7 +261,7 @@ TEST(document_load_string) { pugi::xml_document doc; - CHECK(doc.load(STR(""))); + CHECK(doc.load_string(STR(""))); CHECK_NODE(doc, STR("")); } @@ -308,7 +308,7 @@ TEST(document_load_file_error) TEST(document_load_file_error_previous) { pugi::xml_document doc; - CHECK(doc.load(STR(""))); + CHECK(doc.load_string(STR(""))); CHECK(doc.first_child()); CHECK(doc.load_file("filedoesnotexist").status == status_file_not_found); @@ -590,7 +590,7 @@ TEST(document_parse_result_description) TEST(document_load_fail) { xml_document doc; - CHECK(!doc.load(STR(""))); + CHECK(!doc.load_string(STR(""))); CHECK(doc.child(STR("foo")).child(STR("bar"))); } @@ -1079,7 +1079,7 @@ TEST(document_load_exceptions) try { pugi::xml_document doc; - if (!doc.load(STR("") CHECK(!doc.first_child()); CHECK_NODE(doc, STR("")); - CHECK(doc.load(STR(""))); + CHECK(doc.load_string(STR(""))); CHECK(doc.first_child()); CHECK_NODE(doc, STR("")); @@ -1268,7 +1268,7 @@ TEST(document_alignment) { xml_document* doc = new (buf + offset) xml_document; - CHECK(doc->load(STR(""))); + CHECK(doc->load_string(STR(""))); CHECK_NODE(*doc, STR("")); doc->~xml_document(); @@ -1308,3 +1308,10 @@ TEST(document_convert_out_of_memory) delete[] files[j].data; } } + +TEST(document_deprecated_load) +{ + xml_document doc; + CHECK(doc.load(STR(""))); + CHECK_NODE(doc, STR("")); +} diff --git a/tests/test_dom_modify.cpp b/tests/test_dom_modify.cpp index 45cf3ea..8665af9 100644 --- a/tests/test_dom_modify.cpp +++ b/tests/test_dom_modify.cpp @@ -1289,7 +1289,7 @@ TEST(dom_node_copy_stackless) data += STR(""); xml_document doc; - CHECK(doc.load(data.c_str())); + CHECK(doc.load_string(data.c_str())); xml_document copy; CHECK(copy.append_copy(doc.first_child())); @@ -1324,7 +1324,7 @@ TEST(dom_node_copy_copyless) TEST(dom_node_copy_copyless_mix) { xml_document doc; - CHECK(doc.load(STR("pcdata"), parse_full)); + CHECK(doc.load_string(STR("pcdata"), parse_full)); xml_node child = doc.child(STR("node")).child(STR("child")); diff --git a/tests/test_memory.cpp b/tests/test_memory.cpp index 32d395b..bd80ca1 100644 --- a/tests/test_memory.cpp +++ b/tests/test_memory.cpp @@ -39,7 +39,7 @@ TEST(memory_custom_memory_management) CHECK(allocate_count == 0 && deallocate_count == 0); - CHECK(doc.load(STR(""))); + CHECK(doc.load_string(STR(""))); CHECK(allocate_count == 2 && deallocate_count == 0); diff --git a/tests/test_parse.cpp b/tests/test_parse.cpp index c45b783..321b84c 100644 --- a/tests/test_parse.cpp +++ b/tests/test_parse.cpp @@ -12,10 +12,10 @@ TEST(parse_pi_skip) { unsigned int flags = flag_sets[i]; - CHECK(doc.load(STR(""), flags)); + CHECK(doc.load_string(STR(""), flags)); CHECK(!doc.first_child()); - CHECK(doc.load(STR(" value?>"), flags)); + CHECK(doc.load_string(STR(" value?>"), flags)); CHECK(!doc.first_child()); } } @@ -23,7 +23,7 @@ TEST(parse_pi_skip) TEST(parse_pi_parse) { xml_document doc; - CHECK(doc.load(STR(""), parse_fragment | parse_pi)); + CHECK(doc.load_string(STR(""), parse_fragment | parse_pi)); xml_node pi1 = doc.first_child(); xml_node pi2 = doc.last_child(); @@ -40,7 +40,7 @@ TEST(parse_pi_parse) TEST(parse_pi_parse_spaces) { xml_document doc; - CHECK(doc.load(STR(""), parse_fragment | parse_pi)); + CHECK(doc.load_string(STR(""), parse_fragment | parse_pi)); xml_node pi = doc.first_child(); @@ -59,46 +59,46 @@ TEST(parse_pi_error) { unsigned int flags = flag_sets[i]; - CHECK(doc.load(STR(""), flags).status == status_bad_pi); - CHECK(doc.load(STR(""), flags).status == status_bad_pi); - CHECK(doc.load(STR(""), flags).status == status_bad_pi); - CHECK(doc.load(STR(""), flags).status == status_bad_pi); - CHECK(doc.load(STR(" "), flags).status == status_bad_pi); - CHECK(doc.load(STR(""), flags).status == status_bad_pi); + CHECK(doc.load_string(STR(""), flags).status == status_bad_pi); + CHECK(doc.load_string(STR(""), flags).status == status_bad_pi); + CHECK(doc.load_string(STR(""), flags).status == status_bad_pi); + CHECK(doc.load_string(STR(" "), flags).status == status_bad_pi); + CHECK(doc.load_string(STR(""), parse_fragment | parse_pi).status == status_bad_pi); - CHECK(doc.load(STR(""), parse_fragment | parse_pi).status == status_bad_pi); - CHECK(doc.load(STR(""), parse_fragment | parse_pi).status == status_bad_pi); + CHECK(doc.load_string(STR(""), parse_fragment | parse_pi).status == status_bad_pi); + CHECK(doc.load_string(STR(""), parse_fragment | parse_pi).status == status_bad_pi); + CHECK(doc.load_string(STR(""), parse_fragment | parse_pi).status == status_bad_pi); } TEST(parse_comments_skip) { xml_document doc; - CHECK(doc.load(STR(""), parse_fragment)); + CHECK(doc.load_string(STR(""), parse_fragment)); CHECK(!doc.first_child()); } TEST(parse_comments_parse) { xml_document doc; - CHECK(doc.load(STR(""), parse_fragment | parse_comments)); + CHECK(doc.load_string(STR(""), parse_fragment | parse_comments)); xml_node c1 = doc.first_child(); xml_node c2 = doc.last_child(); @@ -115,7 +115,7 @@ TEST(parse_comments_parse) TEST(parse_comments_parse_no_eol) { xml_document doc; - CHECK(doc.load(STR(""), parse_fragment | parse_comments)); + CHECK(doc.load_string(STR(""), parse_fragment | parse_comments)); xml_node c = doc.first_child(); CHECK(c.type() == node_comment); @@ -125,7 +125,7 @@ TEST(parse_comments_parse_no_eol) TEST(parse_comments_parse_eol) { xml_document doc; - CHECK(doc.load(STR(""), parse_fragment | parse_comments | parse_eol)); + CHECK(doc.load_string(STR(""), parse_fragment | parse_comments | parse_eol)); xml_node c = doc.first_child(); CHECK(c.type() == node_comment); @@ -142,33 +142,33 @@ TEST(parse_comments_error) { unsigned int flags = flag_sets[i]; - CHECK(doc.load(STR(""), flags).status == status_bad_comment); - CHECK(doc.load(STR(""), flags).status == status_bad_comment); - CHECK(doc.load(STR(""), flags).status == status_bad_comment); + CHECK(doc.load_string(STR(""), flags).status == status_bad_comment); + CHECK(doc.load_string(STR(""), flags).status == status_bad_comment); + CHECK(doc.load_string(STR(""), flags).status == status_bad_comment); } } TEST(parse_cdata_skip) { xml_document doc; - CHECK(doc.load(STR(""), parse_fragment)); + CHECK(doc.load_string(STR(""), parse_fragment)); CHECK(!doc.first_child()); } TEST(parse_cdata_skip_contents) { xml_document doc; - CHECK(doc.load(STR("hello, world!"), parse_fragment)); + CHECK(doc.load_string(STR("hello, world!"), parse_fragment)); CHECK_NODE(doc, STR("hello, world!")); } TEST(parse_cdata_parse) { xml_document doc; - CHECK(doc.load(STR(""), parse_fragment | parse_cdata)); + CHECK(doc.load_string(STR(""), parse_fragment | parse_cdata)); xml_node c1 = doc.first_child(); xml_node c2 = doc.last_child(); @@ -185,7 +185,7 @@ TEST(parse_cdata_parse) TEST(parse_cdata_parse_no_eol) { xml_document doc; - CHECK(doc.load(STR(""), parse_fragment | parse_cdata)); + CHECK(doc.load_string(STR(""), parse_fragment | parse_cdata)); xml_node c = doc.first_child(); CHECK(c.type() == node_cdata); @@ -195,7 +195,7 @@ TEST(parse_cdata_parse_no_eol) TEST(parse_cdata_parse_eol) { xml_document doc; - CHECK(doc.load(STR(""), parse_fragment | parse_cdata | parse_eol)); + CHECK(doc.load_string(STR(""), parse_fragment | parse_cdata | parse_eol)); xml_node c = doc.first_child(); CHECK(c.type() == node_cdata); @@ -212,29 +212,29 @@ TEST(parse_cdata_error) { unsigned int flags = flag_sets[i]; - CHECK(doc.load(STR(""), flags).status == status_bad_cdata); - CHECK(doc.load(STR(""), flags).status == status_bad_cdata); + CHECK(doc.load_string(STR(""), flags).status == status_bad_cdata); + CHECK(doc.load_string(STR(""), flags).status == status_bad_cdata); } } TEST(parse_ws_pcdata_skip) { xml_document doc; - CHECK(doc.load(STR(" "), parse_fragment)); + CHECK(doc.load_string(STR(" "), parse_fragment)); CHECK(!doc.first_child()); - CHECK(doc.load(STR(" "), parse_minimal)); + CHECK(doc.load_string(STR(" "), parse_minimal)); xml_node root = doc.child(STR("root")); @@ -245,7 +245,7 @@ TEST(parse_ws_pcdata_skip) TEST(parse_ws_pcdata_parse) { xml_document doc; - CHECK(doc.load(STR(" "), parse_minimal | parse_ws_pcdata)); + CHECK(doc.load_string(STR(" "), parse_minimal | parse_ws_pcdata)); xml_node root = doc.child(STR("root")); @@ -334,7 +334,7 @@ TEST(parse_ws_pcdata_permutations) unsigned int flags[] = {parse_default, parse_default | parse_ws_pcdata, parse_default | parse_ws_pcdata_single}; xml_document doc; - CHECK((td.nodes > 0) == doc.load(td.source, flags[flag])); + CHECK((td.nodes > 0) == doc.load_string(td.source, flags[flag])); CHECK_NODE(doc, td.result); int nodes = get_tree_node_count(doc); @@ -385,7 +385,7 @@ TEST(parse_ws_pcdata_fragment_permutations) unsigned int flags[] = {parse_default, parse_default | parse_ws_pcdata, parse_default | parse_ws_pcdata_single}; xml_document doc; - CHECK((td.nodes > 0) == doc.load(td.source, flags[flag] | parse_fragment)); + CHECK((td.nodes > 0) == doc.load_string(td.source, flags[flag] | parse_fragment)); CHECK_NODE(doc, td.result); int nodes = get_tree_node_count(doc); @@ -398,7 +398,7 @@ TEST(parse_ws_pcdata_fragment_permutations) TEST(parse_pcdata_no_eol) { xml_document doc; - CHECK(doc.load(STR("\r\rval1\rval2\r\nval3\nval4\r\r"), parse_minimal)); + CHECK(doc.load_string(STR("\r\rval1\rval2\r\nval3\nval4\r\r"), parse_minimal)); CHECK_STRING(doc.child_value(STR("root")), STR("\r\rval1\rval2\r\nval3\nval4\r\r")); } @@ -406,7 +406,7 @@ TEST(parse_pcdata_no_eol) TEST(parse_pcdata_eol) { xml_document doc; - CHECK(doc.load(STR("\r\rval1\rval2\r\nval3\nval4\r\r"), parse_minimal | parse_eol)); + CHECK(doc.load_string(STR("\r\rval1\rval2\r\nval3\nval4\r\r"), parse_minimal | parse_eol)); CHECK_STRING(doc.child_value(STR("root")), STR("\n\nval1\nval2\nval3\nval4\n\n")); } @@ -414,7 +414,7 @@ TEST(parse_pcdata_eol) TEST(parse_pcdata_skip_ext) { xml_document doc; - CHECK(doc.load(STR("prepost"), parse_minimal)); + CHECK(doc.load_string(STR("prepost"), parse_minimal)); CHECK(doc.first_child() == doc.last_child()); CHECK(doc.first_child().type() == node_element); } @@ -422,7 +422,7 @@ TEST(parse_pcdata_skip_ext) TEST(parse_pcdata_error) { xml_document doc; - CHECK(doc.load(STR("pcdata"), parse_minimal).status == status_end_element_mismatch); + CHECK(doc.load_string(STR("pcdata"), parse_minimal).status == status_end_element_mismatch); } TEST(parse_pcdata_trim) @@ -460,7 +460,7 @@ TEST(parse_pcdata_trim) const test_data_t& td = test_data[i]; xml_document doc; - CHECK(doc.load(td.source, td.flags | parse_trim_pcdata)); + CHECK(doc.load_string(td.source, td.flags | parse_trim_pcdata)); const pugi::char_t* value = doc.child(STR("node")) ? doc.child_value(STR("node")) : doc.text().get(); CHECK_STRING(value, td.result); @@ -474,7 +474,7 @@ TEST(parse_pcdata_trim_empty) for (size_t i = 0; i < sizeof(flags) / sizeof(flags[0]); ++i) { xml_document doc; - CHECK(doc.load(STR(" "), flags[i] | parse_trim_pcdata)); + CHECK(doc.load_string(STR(" "), flags[i] | parse_trim_pcdata)); xml_node node = doc.child(STR("node")); CHECK(node); @@ -485,14 +485,14 @@ TEST(parse_pcdata_trim_empty) TEST(parse_escapes_skip) { xml_document doc; - CHECK(doc.load(STR("<>&'""), parse_minimal)); + CHECK(doc.load_string(STR("<>&'""), parse_minimal)); CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR("<>&'"")); } TEST(parse_escapes_parse) { xml_document doc; - CHECK(doc.load(STR("<>&'""), parse_minimal | parse_escapes)); + CHECK(doc.load_string(STR("<>&'""), parse_minimal | parse_escapes)); CHECK_STRING(doc.child_value(STR("node")), STR("<>&'\"")); CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR("<>&'\"")); } @@ -500,28 +500,28 @@ TEST(parse_escapes_parse) TEST(parse_escapes_code) { xml_document doc; - CHECK(doc.load(STR(" "), parse_minimal | parse_escapes)); + CHECK(doc.load_string(STR(" "), parse_minimal | parse_escapes)); CHECK_STRING(doc.child_value(STR("node")), STR("\01 ")); } TEST(parse_escapes_code_exhaustive_dec) { xml_document doc; - CHECK(doc.load(STR("&#/; &#:;&#a;&#A; "), parse_minimal | parse_escapes)); + CHECK(doc.load_string(STR("&#/; &#:;&#a;&#A; "), parse_minimal | parse_escapes)); CHECK_STRING(doc.child_value(STR("node")), STR("&#/;\x1\x2\x3\x4\x5\x6\x7\x8\x9&#:;&#a;&#A; ")); } TEST(parse_escapes_code_exhaustive_hex) { xml_document doc; - CHECK(doc.load(STR("&#x/; &#x:;&#x@; &#xG;&#x`; &#xg;"), parse_minimal | parse_escapes)); + CHECK(doc.load_string(STR("&#x/; &#x:;&#x@; &#xG;&#x`; &#xg;"), parse_minimal | parse_escapes)); CHECK_STRING(doc.child_value(STR("node")), STR("&#x/;\x1\x2\x3\x4\x5\x6\x7\x8\x9&#x:;&#x@;\xa\xb\xc\xd\xe\xf&#xG;&#x`;\xa\xb\xc\xd\xe\xf&#xg;")); } TEST(parse_escapes_code_restore) { xml_document doc; - CHECK(doc.load(STR("  - - "), parse_minimal | parse_escapes)); + CHECK(doc.load_string(STR("  - - "), parse_minimal | parse_escapes)); CHECK_STRING(doc.child_value(STR("node")), STR("  - - ")); } @@ -529,26 +529,26 @@ TEST(parse_escapes_char_restore) { xml_document doc; - CHECK(doc.load(STR("&q &qu &quo " "), parse_minimal | parse_escapes)); + CHECK(doc.load_string(STR("&q &qu &quo " "), parse_minimal | parse_escapes)); CHECK_STRING(doc.child_value(STR("node")), STR("&q &qu &quo " ")); - CHECK(doc.load(STR("&a &ap &apo &apos "), parse_minimal | parse_escapes)); + CHECK(doc.load_string(STR("&a &ap &apo &apos "), parse_minimal | parse_escapes)); CHECK_STRING(doc.child_value(STR("node")), STR("&a &ap &apo &apos ")); - CHECK(doc.load(STR("&a &am & "), parse_minimal | parse_escapes)); + CHECK(doc.load_string(STR("&a &am & "), parse_minimal | parse_escapes)); CHECK_STRING(doc.child_value(STR("node")), STR("&a &am & ")); - CHECK(doc.load(STR("&l < "), parse_minimal | parse_escapes)); + CHECK(doc.load_string(STR("&l < "), parse_minimal | parse_escapes)); CHECK_STRING(doc.child_value(STR("node")), STR("&l < ")); - CHECK(doc.load(STR("&g > "), parse_minimal | parse_escapes)); + CHECK(doc.load_string(STR("&g > "), parse_minimal | parse_escapes)); CHECK_STRING(doc.child_value(STR("node")), STR("&g > ")); } TEST(parse_escapes_unicode) { xml_document doc; - CHECK(doc.load(STR("γγ𤭢"), parse_minimal | parse_escapes)); + CHECK(doc.load_string(STR("γγ𤭢"), parse_minimal | parse_escapes)); #ifdef PUGIXML_WCHAR_MODE const pugi::char_t* v = doc.child_value(STR("node")); @@ -564,23 +564,23 @@ TEST(parse_escapes_unicode) TEST(parse_escapes_error) { xml_document doc; - CHECK(doc.load(STR("g;&#ab;""), parse_minimal | parse_escapes)); + CHECK(doc.load_string(STR("g;&#ab;""), parse_minimal | parse_escapes)); CHECK_STRING(doc.child_value(STR("node")), STR("g;&#ab;"")); - CHECK(!doc.load(STR("&#;&#x;&;&#x-;&#-;"), parse_minimal | parse_escapes)); + CHECK(doc.load_string(STR("&#;&#x;&;&#x-;&#-;"), parse_minimal | parse_escapes)); CHECK_STRING(doc.child_value(STR("node")), STR("&#;&#x;&;&#x-;&#-;")); } @@ -598,7 +598,7 @@ TEST(parse_escapes_attribute) flags |= (eol ? parse_eol : 0); flags |= (wconv ? parse_wconv_attribute : 0); - CHECK(doc.load(STR(""), flags)); + CHECK(doc.load_string(STR(""), flags)); CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR("\"")); } } @@ -606,7 +606,7 @@ TEST(parse_escapes_attribute) TEST(parse_attribute_spaces) { xml_document doc; - CHECK(doc.load(STR(""), parse_minimal)); + CHECK(doc.load_string(STR(""), parse_minimal)); CHECK_STRING(doc.child(STR("node")).attribute(STR("id1")).value(), STR("v1")); CHECK_STRING(doc.child(STR("node")).attribute(STR("id2")).value(), STR("v2")); CHECK_STRING(doc.child(STR("node")).attribute(STR("id3")).value(), STR("v3")); @@ -617,7 +617,7 @@ TEST(parse_attribute_spaces) TEST(parse_attribute_quot) { xml_document doc; - CHECK(doc.load(STR(""), parse_minimal)); + CHECK(doc.load_string(STR(""), parse_minimal)); CHECK_STRING(doc.child(STR("node")).attribute(STR("id1")).value(), STR("v1")); CHECK_STRING(doc.child(STR("node")).attribute(STR("id2")).value(), STR("v2")); } @@ -625,28 +625,28 @@ TEST(parse_attribute_quot) TEST(parse_attribute_no_eol_no_wconv) { xml_document doc; - CHECK(doc.load(STR(""), parse_minimal)); + CHECK(doc.load_string(STR(""), parse_minimal)); CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR(" \t\r\rval1 \rval2\r\nval3\nval4\r\r")); } TEST(parse_attribute_eol_no_wconv) { xml_document doc; - CHECK(doc.load(STR(""), parse_minimal | parse_eol)); + CHECK(doc.load_string(STR(""), parse_minimal | parse_eol)); CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR(" \t\n\nval1 \nval2\nval3\nval4\n\n")); } TEST(parse_attribute_no_eol_wconv) { xml_document doc; - CHECK(doc.load(STR(""), parse_minimal | parse_wconv_attribute)); + CHECK(doc.load_string(STR(""), parse_minimal | parse_wconv_attribute)); CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR(" val1 val2 val3 val4 ")); } TEST(parse_attribute_eol_wconv) { xml_document doc; - CHECK(doc.load(STR(""), parse_minimal | parse_eol | parse_wconv_attribute)); + CHECK(doc.load_string(STR(""), parse_minimal | parse_eol | parse_wconv_attribute)); CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR(" val1 val2 val3 val4 ")); } @@ -658,7 +658,7 @@ TEST(parse_attribute_wnorm) for (int wconv = 0; wconv < 2; ++wconv) { unsigned int flags = parse_minimal | parse_wnorm_attribute | (eol ? parse_eol : 0) | (wconv ? parse_wconv_attribute : 0); - CHECK(doc.load(STR(""), flags)); + CHECK(doc.load_string(STR(""), flags)); CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR("val1 val2 val3 val4")); } } @@ -679,7 +679,7 @@ TEST(parse_attribute_variations) flags |= (wconv ? parse_wconv_attribute : 0); flags |= (escapes ? parse_escapes : 0); - CHECK(doc.load(STR(""), flags)); + CHECK(doc.load_string(STR(""), flags)); CHECK_STRING(doc.child(STR("node")).attribute(STR("id")).value(), STR("1")); } } @@ -688,24 +688,24 @@ TEST(parse_attribute_variations) TEST(parse_attribute_error) { xml_document doc; - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_attribute); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_attribute); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_attribute); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_attribute); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_attribute); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_start_element); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_start_element); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_attribute); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_attribute); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_start_element); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_bad_attribute); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_bad_attribute); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_bad_attribute); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_bad_attribute); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_bad_attribute); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_bad_start_element); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_bad_start_element); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_bad_attribute); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_bad_attribute); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_bad_start_element); } TEST(parse_attribute_termination_error) @@ -722,7 +722,7 @@ TEST(parse_attribute_termination_error) flags |= (eol ? parse_eol : 0); flags |= (wconv ? parse_wconv_attribute : 0); - CHECK(doc.load(STR(""), flags)); + CHECK(doc.load_string(STR(""), flags)); CHECK_STRING(doc.child(STR("node")).attribute(STR("id1")).value(), STR("\"")); CHECK_STRING(doc.child(STR("node")).attribute(STR("id2")).value(), STR("'")); } @@ -749,60 +749,60 @@ TEST(parse_attribute_quot_inside) TEST(parse_tag_single) { xml_document doc; - CHECK(doc.load(STR(""), parse_minimal)); + CHECK(doc.load_string(STR(""), parse_minimal)); CHECK_NODE(doc, STR("")); } TEST(parse_tag_hierarchy) { xml_document doc; - CHECK(doc.load(STR(""), parse_minimal)); + CHECK(doc.load_string(STR(""), parse_minimal)); CHECK_NODE(doc, STR("")); } TEST(parse_tag_error) { xml_document doc; - CHECK(doc.load(STR("<"), parse_minimal).status == status_unrecognized_tag); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_start_element); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_start_element); - CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); - CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); - CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); - CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); - CHECK(doc.load(STR("<"), parse_minimal).status == status_unrecognized_tag); - CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); - CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); - CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); - CHECK(doc.load(STR(""), parse_minimal).status == status_end_element_mismatch); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_end_element); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_start_element); - CHECK(doc.load(STR(""), parse_minimal).status == status_bad_start_element); + CHECK(doc.load_string(STR("<"), parse_minimal).status == status_unrecognized_tag); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_bad_start_element); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_bad_start_element); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_end_element_mismatch); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_end_element_mismatch); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_end_element_mismatch); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_end_element_mismatch); + CHECK(doc.load_string(STR("<"), parse_minimal).status == status_unrecognized_tag); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_end_element_mismatch); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_end_element_mismatch); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_end_element_mismatch); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_end_element_mismatch); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_bad_end_element); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_bad_start_element); + CHECK(doc.load_string(STR(""), parse_minimal).status == status_bad_start_element); } TEST(parse_declaration_cases) { xml_document doc; - CHECK(doc.load(STR(""), parse_fragment | parse_pi)); + CHECK(doc.load_string(STR(""), parse_fragment | parse_pi)); CHECK(!doc.first_child()); } TEST(parse_declaration_attr_cases) { xml_document doc; - CHECK(doc.load(STR(""), parse_fragment | parse_pi)); + CHECK(doc.load_string(STR(""), parse_fragment | parse_pi)); CHECK(!doc.first_child()); } @@ -816,10 +816,10 @@ TEST(parse_declaration_skip) { unsigned int flags = flag_sets[i]; - CHECK(doc.load(STR(""), flags)); + CHECK(doc.load_string(STR(""), flags)); CHECK(!doc.first_child()); - CHECK(doc.load(STR(" ?>"), flags)); + CHECK(doc.load_string(STR(" ?>"), flags)); CHECK(!doc.first_child()); } } @@ -827,7 +827,7 @@ TEST(parse_declaration_skip) TEST(parse_declaration_parse) { xml_document doc; - CHECK(doc.load(STR(""), parse_fragment | parse_declaration)); + CHECK(doc.load_string(STR(""), parse_fragment | parse_declaration)); xml_node d1 = doc.first_child(); xml_node d2 = doc.last_child(); @@ -850,21 +850,21 @@ TEST(parse_declaration_error) { unsigned int flags = flag_sets[i]; - CHECK(doc.load(STR(""), flags).status == status_bad_pi); - CHECK(doc.load(STR(""), flags).status == status_bad_pi); + CHECK(doc.load_string(STR(""), flags).status == status_bad_pi); + CHECK(doc.load_string(STR(""), flags).status == status_bad_pi); } - CHECK(doc.load(STR(""), parse_fragment | parse_declaration).status == status_bad_attribute); - CHECK(doc.load(STR(""), parse_fragment | parse_declaration).status == status_bad_pi); + CHECK(doc.load_string(STR(""), parse_fragment | parse_declaration).status == status_bad_attribute); + CHECK(doc.load_string(STR(""), parse_fragment | parse_declaration).status == status_bad_pi); } TEST(parse_empty) { xml_document doc; - CHECK(doc.load(STR("")).status == status_no_document_element && !doc.first_child()); - CHECK(doc.load(STR(""), parse_fragment) && !doc.first_child()); + CHECK(doc.load_string(STR("")).status == status_no_document_element && !doc.first_child()); + CHECK(doc.load_string(STR(""), parse_fragment) && !doc.first_child()); } TEST(parse_out_of_memory) @@ -872,7 +872,7 @@ TEST(parse_out_of_memory) test_runner::_memory_fail_threshold = 256; xml_document doc; - CHECK(doc.load(STR("")).status == status_out_of_memory); + CHECK(doc.load_string(STR("")).status == status_out_of_memory); CHECK(!doc.first_child()); } @@ -928,7 +928,7 @@ TEST(parse_out_of_memory_halfway_attr) static bool test_offset(const char_t* contents, unsigned int options, pugi::xml_parse_status status, ptrdiff_t offset) { xml_document doc; - xml_parse_result res = doc.load(contents, options); + xml_parse_result res = doc.load_string(contents, options); return res.status == status && res.offset == offset; } @@ -1065,7 +1065,7 @@ TEST(parse_bom_fragment_invalid_utf32) TEST(parse_pcdata_gap_fragment) { xml_document doc; - CHECK(doc.load(STR("a&b"), parse_fragment | parse_escapes)); + CHECK(doc.load_string(STR("a&b"), parse_fragment | parse_escapes)); CHECK_STRING(doc.text().get(), STR("a&b")); } diff --git a/tests/test_parse_doctype.cpp b/tests/test_parse_doctype.cpp index f8619fd..14268f6 100644 --- a/tests/test_parse_doctype.cpp +++ b/tests/test_parse_doctype.cpp @@ -20,7 +20,7 @@ static xml_parse_result load_concat(xml_document& doc, const char_t* a, const ch strcat(buffer, c); #endif - return doc.load(buffer, parse_fragment); + return doc.load_string(buffer, parse_fragment); } static bool test_doctype_wf(const char_t* decl) @@ -41,7 +41,7 @@ static bool test_doctype_wf(const char_t* decl) if (!load_concat(doc, STR(""), decl, STR("")) || !test_node(doc, STR(""), STR(""), format_raw)) return false; // check load-store contents preservation - CHECK(doc.load(decl, parse_doctype | parse_fragment)); + CHECK(doc.load_string(decl, parse_doctype | parse_fragment)); CHECK_NODE(doc, decl); return true; @@ -281,8 +281,8 @@ TEST(parse_doctype_xmlconf_oasis_1) // not actually a doctype :) xml_document doc; - CHECK(doc.load(STR(" "), parse_full | parse_fragment) && doc.first_child().type() == node_comment && doc.last_child().type() == node_comment && doc.first_child().next_sibling() == doc.last_child()); - CHECK(doc.load(STR(" &a%b&#c?>"), parse_full | parse_fragment) && doc.first_child().type() == node_pi && doc.first_child() == doc.last_child()); + CHECK(doc.load_string(STR(" "), parse_full | parse_fragment) && doc.first_child().type() == node_comment && doc.last_child().type() == node_comment && doc.first_child().next_sibling() == doc.last_child()); + CHECK(doc.load_string(STR(" &a%b&#c?>"), parse_full | parse_fragment) && doc.first_child().type() == node_pi && doc.first_child() == doc.last_child()); } TEST(parse_doctype_xmlconf_xmltest_1) @@ -310,15 +310,15 @@ TEST_XML_FLAGS(parse_doctype_value, " ")).status == status_bad_doctype); - CHECK(doc.load(STR(""), parse_doctype).status == status_bad_doctype); + CHECK(doc.load_string(STR("")).status == status_bad_doctype); + CHECK(doc.load_string(STR(""), parse_doctype).status == status_bad_doctype); } TEST(parse_doctype_error_ignore) { xml_document doc; - CHECK(doc.load(STR(""); xml_document doc; - CHECK(doc.load(data.c_str())); + CHECK(doc.load_string(data.c_str())); CHECK_NODE(doc, data.c_str()); } diff --git a/tests/test_xpath.cpp b/tests/test_xpath.cpp index a65ee37..e410882 100644 --- a/tests/test_xpath.cpp +++ b/tests/test_xpath.cpp @@ -13,7 +13,7 @@ static void load_document_copy(xml_document& doc, const char_t* text) { xml_document source; - CHECK(source.load(text)); + CHECK(source.load_string(text)); doc.append_copy(source.first_child()); } @@ -551,10 +551,10 @@ TEST_XML(xpath_sort_append_buffer, "") TEST(xpath_sort_crossdoc) { xml_document doc1; - CHECK(doc1.load(STR(""))); + CHECK(doc1.load_string(STR(""))); xml_document doc2; - CHECK(doc2.load(STR(""))); + CHECK(doc2.load_string(STR(""))); xpath_node_set ns1 = doc1.select_nodes(STR("*")); CHECK(ns1.size() == 1); -- cgit v1.2.3 From b041e94f29fee9800f02ca6c257fe6cea4eae72a Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Mon, 17 Nov 2014 21:47:37 -0800 Subject: Update version to 1.5 --- Jamfile.jam | 2 +- docs/manual.qbk | 10 +++++----- docs/quickstart.qbk | 8 ++++---- readme.txt | 2 +- scripts/CMakeLists.txt | 2 +- src/pugiconfig.hpp | 2 +- src/pugixml.cpp | 2 +- src/pugixml.hpp | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Jamfile.jam b/Jamfile.jam index d85188d..512e2c9 100644 --- a/Jamfile.jam +++ b/Jamfile.jam @@ -144,7 +144,7 @@ for SAMPLE in [ Glob docs/samples : *.cpp ] } # release -VERSION = 1.4 ; +VERSION = 1.5 ; RELEASE_FILES = [ Glob contrib : *.cpp *.hpp ] [ Glob src : *.cpp *.hpp ] diff --git a/docs/manual.qbk b/docs/manual.qbk index 6d7f4e1..dde8b52 100644 --- a/docs/manual.qbk +++ b/docs/manual.qbk @@ -1,7 +1,7 @@ [book pugixml [quickbook 1.5] - [version 1.4] + [version 1.5] [id manual] [copyright 2014 Arseny Kapoulkine] [license Distributed under the MIT License] @@ -106,8 +106,8 @@ pugixml is distributed in source form. You can either download a source distribu You can download the latest source distribution via one of the following links: [pre -[@https://github.com/zeux/pugixml/releases/download/v1.4/pugixml-1.4.zip] -[@https://github.com/zeux/pugixml/releases/download/v1.4/pugixml-1.4.tar.gz] +[@https://github.com/zeux/pugixml/releases/download/v1.5/pugixml-1.5.zip] +[@https://github.com/zeux/pugixml/releases/download/v1.5/pugixml-1.5.tar.gz] ] The distribution contains library source, documentation (the manual you're reading now and the quick start guide) and some code examples. After downloading the distribution, install pugixml by extracting all files from the compressed archive. The files have different line endings depending on the archive format - [file .zip] archive has Windows line endings, [file .tar.gz] archive has Unix line endings. Otherwise the files in both archives are identical. @@ -125,7 +125,7 @@ For example, to checkout the current version, you can use this command: [pre git clone https://github.com/zeux/pugixml cd pugixml -git checkout v1.4 +git checkout v1.5 ] The repository contains library source, documentation, code examples and full unit test suite. @@ -138,7 +138,7 @@ Use latest version tag if you want to automatically get new versions. Use other You can access the Git repository via Subversion using [@https://github.com/zeux/pugixml] URL. For example, to checkout the current version, you can use this command: -[pre svn checkout https://github.com/zeux/pugixml/tags/v1.4 pugixml] +[pre svn checkout https://github.com/zeux/pugixml/tags/v1.5 pugixml] [endsect] [/subversion] diff --git a/docs/quickstart.qbk b/docs/quickstart.qbk index c913ccb..1845224 100644 --- a/docs/quickstart.qbk +++ b/docs/quickstart.qbk @@ -1,7 +1,7 @@ [article pugixml [quickbook 1.5] - [version 1.4] + [version 1.5] [id quickstart] [copyright 2014 Arseny Kapoulkine] [license Distributed under the MIT License] @@ -11,7 +11,7 @@ [template sref[name]''''''] [template ftnt[id text]''''''[text]''''''] -[section:main pugixml 1.4 quick start guide] +[section:main pugixml 1.5 quick start guide] [section:introduction Introduction] @@ -30,8 +30,8 @@ This is the quick start guide for pugixml, which purpose is to enable you to sta pugixml is distributed in source form. You can download a source distribution via one of the following links: [pre -[@https://github.com/zeux/pugixml/releases/download/v1.4/pugixml-1.4.zip] -[@https://github.com/zeux/pugixml/releases/download/v1.4/pugixml-1.4.tar.gz] +[@https://github.com/zeux/pugixml/releases/download/v1.5/pugixml-1.5.zip] +[@https://github.com/zeux/pugixml/releases/download/v1.5/pugixml-1.5.tar.gz] ] The distribution contains library source, documentation (the guide you're reading now and the manual) and some code examples. After downloading the distribution, install pugixml by extracting all files from the compressed archive. The files have different line endings depending on the archive format - [file .zip] archive has Windows line endings, [file .tar.gz] archive has Unix line endings. Otherwise the files in both archives are identical. diff --git a/readme.txt b/readme.txt index 5f3e694..54d2a6c 100644 --- a/readme.txt +++ b/readme.txt @@ -1,4 +1,4 @@ -pugixml 1.4 - an XML processing library +pugixml 1.5 - an XML processing library Copyright (C) 2006-2014, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) Report bugs and download new versions at http://pugixml.org/ diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index bd33220..daf6b35 100644 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -22,7 +22,7 @@ else() add_library(pugixml STATIC ${SOURCES}) endif() -set_target_properties(pugixml PROPERTIES VERSION 1.4 SOVERSION 1) +set_target_properties(pugixml PROPERTIES VERSION 1.5 SOVERSION 1) install(TARGETS pugixml EXPORT pugixml-config ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} diff --git a/src/pugiconfig.hpp b/src/pugiconfig.hpp index 56f1d22..1c216e3 100644 --- a/src/pugiconfig.hpp +++ b/src/pugiconfig.hpp @@ -1,5 +1,5 @@ /** - * pugixml parser - version 1.4 + * pugixml parser - version 1.5 * -------------------------------------------------------- * Copyright (C) 2006-2014, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at http://pugixml.org/ diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 852ccb9..3f6b2fd 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -1,6 +1,6 @@ /** { - * pugixml parser - version 1.4 + * pugixml parser - version 1.5 * -------------------------------------------------------- * Copyright (C) 2006-2014, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at http://pugixml.org/ diff --git a/src/pugixml.hpp b/src/pugixml.hpp index 7f52975..917ef4a 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -1,5 +1,5 @@ /** - * pugixml parser - version 1.4 + * pugixml parser - version 1.5 * -------------------------------------------------------- * Copyright (C) 2006-2014, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at http://pugixml.org/ @@ -13,7 +13,7 @@ #ifndef PUGIXML_VERSION // Define version macro; evaluates to major * 100 + minor so that it's safe to use in less-than comparisons -# define PUGIXML_VERSION 140 +# define PUGIXML_VERSION 150 #endif // Include user configuration file (this can define various configuration macros) -- cgit v1.2.3 From 0749d53613f49e5422c4ba125ca4026e1ceced77 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Mon, 17 Nov 2014 22:34:17 -0800 Subject: docs: Add changelog for 1.5 Release date is (tentatively) 11/27. --- docs/manual.qbk | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/docs/manual.qbk b/docs/manual.qbk index dde8b52..b703948 100644 --- a/docs/manual.qbk +++ b/docs/manual.qbk @@ -1892,6 +1892,37 @@ Because of the differences in document object models, performance considerations [section:changes Changelog] +[h5 27.11.2014 - version 1.5] + +Major release, featuring a lot of performance improvements and some new features. + +* Specification changes: + # xml_document::load(const char_t*) was renamed to load_string; the old method is still available and will be deprecated in a future release + # xml_node::select_single_node was renamed to select_node; the old method is still available and will be deprecated in a future release. + +* New features: + # Added xml_node::append_move and other functions for moving nodes within a document + # Added xpath_query::evaluate_node for evaluating queries with a single node as a result + +* Performance improvements: + # Optimized XML parsing (10-40% faster with clang/gcc, up to 10% faster with MSVC) + # Optimized memory consumption when copying nodes in the same document (string contents is now shared) + # Optimized node copying (10% faster for cross-document copies, 3x faster for inter-document copies; also it now consumes a constant amount of stack space) + # Optimized node output (60% faster; also it now consumes a constant amount of stack space) + # Optimized XPath allocation (query evaluation now results in fewer temporary allocations) + # Optimized XPath sorting (node set sorting is 2-3x faster in some cases) + # Optimized XPath evaluation (XPathMark suite is 100x faster; some commonly used queries are 3-4x faster) + +* Compatibility improvements: + # Fixed xml_node::offset_debug for corner cases + # Fixed undefined behavior while calling memcpy in some cases + # Fixed MSVC 2015 compilation warnings + # Fixed contrib/foreach.hpp for Boost 1.56.0 + +* Bug fixes + # Adjusted comment output to avoid malformed documents if the comment value contains "--" + # Fix XPath sorting for documents that were constructed using append_buffer + [h5 27.02.2014 - version 1.4] Major release, featuring various new features, bug fixes and compatibility improvements. -- cgit v1.2.3 From 3c048bbb5e64605cc4e3aa15e0a536eaf00f3c6f Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Mon, 17 Nov 2014 22:45:38 -0800 Subject: tests: Fix version test --- tests/test_version.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_version.cpp b/tests/test_version.cpp index 622a100..24036fc 100644 --- a/tests/test_version.cpp +++ b/tests/test_version.cpp @@ -1,5 +1,5 @@ #include "../src/pugixml.hpp" -#if PUGIXML_VERSION != 140 +#if PUGIXML_VERSION != 150 #error Unexpected pugixml version #endif -- cgit v1.2.3 From 1a06d7d3de3d2f30eaf3d56b7b2d0fa3446d46d8 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Tue, 18 Nov 2014 09:30:19 -0800 Subject: docs: Regenerated documentation Also fix documentation jam rules for Windows. --- Jamrules.jam | 4 +- docs/manual.html | 36 ++--- docs/manual/access.html | 293 +++++++++++++++++++------------------- docs/manual/apiref.html | 138 ++++++++++++++++-- docs/manual/changes.html | 193 ++++++++++++++++++------- docs/manual/dom.html | 196 ++++++++++++------------- docs/manual/install.html | 118 ++++++++------- docs/manual/loading.html | 260 +++++++++++++++++---------------- docs/manual/modify.html | 252 +++++++++++++++++++------------- docs/manual/saving.html | 214 ++++++++++++++-------------- docs/manual/toc.html | 157 ++++++++++---------- docs/manual/xpath.html | 363 +++++++++++++++++++++++------------------------ docs/quickstart.html | 159 ++++++++++++--------- 13 files changed, 1328 insertions(+), 1055 deletions(-) diff --git a/Jamrules.jam b/Jamrules.jam index ab960c7..c1647cb 100644 --- a/Jamrules.jam +++ b/Jamrules.jam @@ -839,8 +839,8 @@ else if ( $(OS) = NT ) { - QUICKBOOK = %QUICKBOOK_PATH%\bin\quickbook.exe ; - XSLTPROC = %QUICKBOOK_PATH%\bin\xsltproc.exe ; + QUICKBOOK = %QUICKBOOK_PATH%bin\\quickbook.exe ; + XSLTPROC = %QUICKBOOK_PATH%bin\\xsltproc.exe ; } else { diff --git a/docs/manual.html b/docs/manual.html index ecac884..64c1c90 100644 --- a/docs/manual.html +++ b/docs/manual.html @@ -1,16 +1,16 @@ -pugixml 1.4 +pugixml 1.5 - +
-pugixml 1.4 manual | +pugixml 1.5 manual | Overview | Installation | Document: @@ -24,17 +24,17 @@

No documentation is perfect, neither is this one. If you encounter a description - that is unclear, please file an issue as described in Feedback. + that is unclear, please file an issue as described in Feedback. Also if you can spare the time for a full proof-reading, including spelling and grammar, that would be great! Please send me an e-mail; as a token of appreciation, your name will be included @@ -80,7 +80,7 @@

If you believe you've found a bug in pugixml (bugs include compilation problems @@ -107,14 +107,14 @@ Your contribution has to be distributed under the terms of a license that's compatible with pugixml license; i.e. GPL/LGPL licensed code is not accepted.

-

- If filing an issue is not possible due to privacy or - other concerns, you can contact pugixml author by e-mail directly: arseny.kapoulkine@gmail.com. +

+ If filing an issue is not possible due to privacy or other concerns, you + can contact pugixml author by e-mail directly: arseny.kapoulkine@gmail.com.

pugixml could not be developed without the help from many people; some of @@ -140,7 +140,7 @@

The pugixml library is distributed under the MIT license: @@ -184,13 +184,13 @@ pugixml

- +

Last revised: February 28, 2014 at 06:00:02 GMT

Last revised: November 18, 2014 at 17:25:31 GMT


-pugixml 1.4 manual | +pugixml 1.5 manual | Overview | Installation | Document: diff --git a/docs/manual/access.html b/docs/manual/access.html index 4d4e9c2..8942a26 100644 --- a/docs/manual/access.html +++ b/docs/manual/access.html @@ -4,15 +4,15 @@ Accessing document data - - + +
-pugixml 1.4 manual | +pugixml 1.5 manual | Overview | Installation | Document: @@ -28,27 +28,27 @@

pugixml features an extensive interface for getting various types of data from the document and for traversing the document. This section provides documentation for all such functions that do not modify the tree except for XPath-related - functions; see XPath for XPath reference. As discussed in C++ interface, + functions; see XPath for XPath reference. As discussed in C++ interface, there are two types of handles to tree data - xml_node and xml_attribute. The handles have special null (empty) values which propagate through various functions and thus are @@ -58,12 +58,11 @@

-

- The - internal representation of the document is a tree, where each node has a - list of child nodes (the order of children corresponds to their order in +

+ The internal representation of the document is a tree, where each node has + a list of child nodes (the order of children corresponds to their order in the XML representation), and additionally element nodes have a list of attributes, which is also ordered. Several functions are provided in order to let you get from one node in the tree to the other. These functions roughly correspond @@ -124,6 +123,7 @@ all attributes like this (samples/traverse_base.cpp):

+

for (pugi::xml_node tool = tools.first_child(); tool; tool = tool.next_sibling())
 {
@@ -142,15 +142,15 @@
 
-

- Apart from structural - information (parent, child nodes, attributes), 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 a name - or value, node_element and node_declaration - nodes always have a name but never have a value, node_pcdata, +

+ Apart from structural information (parent, child nodes, attributes), 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 a name or value, node_element + and node_declaration nodes always + have a name but never have a value, node_pcdata, node_cdata, node_comment and node_doctype nodes never have a name but always have a value (it may be empty though), node_pi @@ -164,9 +164,8 @@ In case node does not have a name or value or if the node handle is null, both functions return empty strings - they never return null pointers.

-

- It is common to store data as text contents - of some node - i.e. <node><description>This is a node</description></node>. +

+ It is common to store data as text contents of some node - i.e. <node><description>This is a node</description></node>. In this case, <description> node does not have a value, but instead has a child of type node_pcdata with value "This is a node". pugixml @@ -189,7 +188,7 @@ text() returns a special object that can be used for working with PCDATA contents in more complex cases than just retrieving the value; it is described in - Working with text contents sections. + Working with text contents sections.

There is an example of using some of these functions at @@ -198,12 +197,11 @@

-

- All - attributes have name and value, both of which are strings (value may be empty). - There are two corresponding accessors, like for xml_node: +

+ All attributes have name and value, both of which are strings (value may + be empty). There are two corresponding accessors, like for xml_node:

const char_t* xml_attribute::name() const;
 const char_t* xml_attribute::value() const;
@@ -212,12 +210,12 @@
         In case the attribute handle is null, both functions return empty strings
         - they never return null pointers.
       

-

- If you need a non-empty string if - the attribute handle is null (for example, you need to get the option value - from XML attribute, but if it is not specified, you need it to default to - "sorted" instead of - ""), you can use as_string accessor: +

+ If you need a non-empty string if the attribute handle is null (for example, + you need to get the option value from XML attribute, but if it is not specified, + you need it to default to "sorted" + instead of ""), you + can use as_string accessor:

const char_t* xml_attribute::as_string(const char_t* def = "") const;
 
@@ -226,12 +224,11 @@ the attribute handle is null. If you do not specify the argument, the function is equivalent to value().

-

- In many cases attribute values have types - that are not strings - i.e. an attribute may always contain values that should - be treated as integers, despite the fact that they are represented as strings - in XML. pugixml provides several accessors that convert attribute value to - some other type: +

+ In many cases attribute values have types that are not strings - i.e. an + attribute may always contain values that should be treated as integers, despite + the fact that they are represented as strings in XML. pugixml provides several + accessors that convert attribute value to some other type:

int xml_attribute::as_int(int def = 0) const;
 unsigned int xml_attribute::as_uint(unsigned int def = 0) const;
@@ -296,11 +293,12 @@
           long type, including string conversions.
         

-

- This is an example of using these functions, - along with node data retrieval ones (samples/traverse_base.cpp): +

+ This is an example of using these functions, along with node data retrieval + ones (samples/traverse_base.cpp):

+

for (pugi::xml_node tool = tools.child("Tool"); tool; tool = tool.next_sibling("Tool"))
 {
@@ -315,12 +313,11 @@
 
 
-

- Since a lot of document traversal consists - of finding the node/attribute with the correct name, there are special functions - for that purpose: +

+ Since a lot of document traversal consists of finding the node/attribute + with the correct name, there are special functions for that purpose:

xml_node xml_node::child(const char_t* name) const;
 xml_attribute xml_node::attribute(const char_t* name) const;
@@ -342,15 +339,11 @@
       

for (pugi::xml_node tool = tools.child("Tool"); tool; tool = tool.next_sibling("Tool"))
 
-

- Occasionally the needed node - is specified not by the unique name but instead by the value of some attribute; - for example, it is common to have node collections with each node having - a unique id: <group><item - id="1"/> - <item - id="2"/></group>. - There are two functions for finding child nodes based on the attribute values: +

+ Occasionally the needed node is specified not by the unique name but instead + by the value of some attribute; for example, it is common to have node collections + with each node having a unique id: <group><item id="1"/> <item id="2"/></group>. There are two functions for finding + child nodes based on the attribute values:

xml_node xml_node::find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const;
 xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const;
@@ -370,6 +363,7 @@
         This is an example of using these functions (samples/traverse_base.cpp):
       

+

std::cout << "Tool for *.dae generation: " << tools.find_child_by_attribute("Tool", "OutputFileMasks", "*.dae").attribute("Filename").value() << "\n";
 
@@ -383,13 +377,12 @@
 
-

- If your - C++ compiler supports range-based for-loop (this is a C++11 feature, at the - time of writing it's supported by Microsoft Visual Studio 11 Beta, GCC 4.6 - and Clang 3.0), you can use it to enumerate nodes/attributes. Additional +

+ If your C++ compiler supports range-based for-loop (this is a C++11 feature, + at the time of writing it's supported by Microsoft Visual Studio 11 Beta, + GCC 4.6 and Clang 3.0), you can use it to enumerate nodes/attributes. Additional helpers are provided to support this; note that they are also compatible with Boost Foreach, and possibly other pre-C++11 foreach facilities. @@ -410,6 +403,7 @@ This is an example of using these functions (samples/traverse_rangefor.cpp):

+

for (pugi::xml_node tool: tools.children("Tool"))
 {
@@ -433,12 +427,12 @@
 
-

- Child node lists and attribute lists are simply - double-linked lists; while you can use previous_sibling/next_sibling and other such functions for +

+ Child node lists and attribute lists are simply double-linked lists; while + you can use previous_sibling/next_sibling and other such functions for iteration, pugixml additionally provides node and attribute iterators, so that you can treat nodes as containers of other nodes or attributes:

@@ -486,6 +480,7 @@ Here is an example of using iterators for document traversal (samples/traverse_iter.cpp):

+

for (pugi::xml_node_iterator it = tools.begin(); it != tools.end(); ++it)
 {
@@ -518,14 +513,14 @@
 
-

- The methods described above allow traversal - of immediate children of some node; if you want to do a deep tree traversal, - you'll have to do it via a recursive function or some equivalent method. - However, pugixml provides a helper for depth-first traversal of a subtree. - In order to use it, you have to implement xml_tree_walker +

+ The methods described above allow traversal of immediate children of some + node; if you want to do a deep tree traversal, you'll have to do it via a + recursive function or some equivalent method. However, pugixml provides a + helper for depth-first traversal of a subtree. In order to use it, you have + to implement xml_tree_walker interface and to call traverse function:

@@ -541,9 +536,8 @@ bool xml_node::traverse(xml_tree_walker& walker);
-

- The traversal - is launched by calling traverse +

+ The traversal is launched by calling traverse function on traversal root and proceeds as follows:

    @@ -570,10 +564,10 @@ begin or end functions; their default implementations return true.

    -

    - You can get the node's depth relative - to the traversal root at any point by calling depth - function. It returns -1 +

    + You can get the node's depth relative to the traversal root at any point + by calling depth function. + It returns -1 if called from begin/end, and returns 0-based depth if called from for_each - depth is 0 for all children of the traversal root, 1 for all grandchildren and so @@ -583,22 +577,24 @@ This is an example of traversing tree hierarchy with xml_tree_walker (samples/traverse_walker.cpp):

    +

    struct simple_walker: pugi::xml_tree_walker
     {
         virtual bool for_each(pugi::xml_node& node)
         {
    -        for (int i = 0; i < depth(); ++i) std::cout << "  "; // indentation
    -
    +        for (int i = 0; i < depth(); ++i) std::cout << "  "; // indentation
    +
             std::cout << node_types[node.type()] << ": name='" << node.name() << "', value='" << node.value() << "'\n";
     
    -        return true; // continue traversal
    -    }
    +        return true; // continue traversal
    +    }
     };
     

    +

    simple_walker walker;
     doc.traverse(walker);
    @@ -608,15 +604,15 @@
     
-

- While there are existing functions for getting - a node/attribute with known contents, they are often not sufficient for simple - queries. As an alternative for manual iteration through nodes/attributes - until the needed one is found, you can make a predicate and call one of - find_ functions: +

+ While there are existing functions for getting a node/attribute with known + contents, they are often not sufficient for simple queries. As an alternative + for manual iteration through nodes/attributes until the needed one is found, + you can make a predicate and call one of find_ + functions:

template <typename Predicate> xml_attribute xml_node::find_attribute(Predicate pred) const;
 template <typename Predicate> xml_node xml_node::find_child(Predicate pred) const;
@@ -658,6 +654,7 @@
         This is an example of using predicate-based functions (samples/traverse_predicate.cpp):
       

+

bool small_timeout(pugi::xml_node node)
 {
@@ -680,29 +677,29 @@
 

+

-
// Find child via predicate (looks for direct children only)
-std::cout << tools.find_child(allow_remote_predicate()).attribute("Filename").value() << std::endl;
+
// Find child via predicate (looks for direct children only)
+std::cout << tools.find_child(allow_remote_predicate()).attribute("Filename").value() << std::endl;
 
-// Find node via predicate (looks for all descendants in depth-first order)
-std::cout << doc.find_node(allow_remote_predicate()).attribute("Filename").value() << std::endl;
+// Find node via predicate (looks for all descendants in depth-first order)
+std::cout << doc.find_node(allow_remote_predicate()).attribute("Filename").value() << std::endl;
 
-// Find attribute via predicate
-std::cout << tools.last_child().find_attribute(allow_remote_predicate()).value() << std::endl;
+// Find attribute via predicate
+std::cout << tools.last_child().find_attribute(allow_remote_predicate()).value() << std::endl;
 
-// We can use simple functions instead of function objects
-std::cout << tools.find_child(small_timeout).attribute("Filename").value() << std::endl;
+// We can use simple functions instead of function objects
+std::cout << tools.find_child(small_timeout).attribute("Filename").value() << std::endl;
 

-

- It is common to store data as text contents of some - node - i.e. <node><description>This is a node</description></node>. +

+ It is common to store data as text contents of some node - i.e. <node><description>This is a node</description></node>. In this case, <description> node does not have a value, but instead has a child of type node_pcdata with value "This is a node". pugixml @@ -711,10 +708,8 @@ in the documentation for modifying document data; this section describes the access interface of xml_text.

-

- You can get the text object from a node by using - text() - method: +

+ You can get the text object from a node by using text() method:

xml_text xml_node::text() const;
 
@@ -724,11 +719,11 @@ itself is used to return data; otherwise, a first child node of type node_pcdata or node_cdata is used.

-

- You - can check if the text object is bound to a valid PCDATA/CDATA node by using - it as a boolean value, i.e. if (text) - { ... } or if +

+ You can check if the text object is bound to a valid PCDATA/CDATA node by + using it as a boolean value, i.e. if + (text) { ... + } or if (!text) { ... }. Alternatively you can check it by using the empty() @@ -736,9 +731,9 @@

bool xml_text::empty() const;
 
-

- Given a text object, you can get the contents - (i.e. the value of PCDATA/CDATA node) by using the following function: +

+ Given a text object, you can get the contents (i.e. the value of PCDATA/CDATA + node) by using the following function:

const char_t* xml_text::get() const;
 
@@ -746,11 +741,10 @@ In case text object is empty, the function returns an empty string - it never returns a null pointer.

-

- If - you need a non-empty string if the text object is empty, or if the text contents - is actually a number or a boolean that is stored as a string, you can use - the following accessors: +

+ If you need a non-empty string if the text object is empty, or if the text + contents is actually a number or a boolean that is stored as a string, you + can use the following accessors:

const char_t* xml_text::as_string(const char_t* def = "") const;
 int xml_text::as_int(int def = 0) const;
@@ -767,9 +761,9 @@
         to a target type using the same rules and restrictions. You can refer
         to documentation for the attribute functions for details.
       

-

- xml_text - is essentially a helper class that operates on xml_node +

+ xml_text is essentially a + helper class that operates on xml_node values. It is bound to a node of type node_pcdata or node_cdata. You can use the following function to retrieve this node: @@ -787,6 +781,7 @@ object (samples/text.cpp):

+

std::cout << "Project name: " << project.child("name").text().get() << std::endl;
 std::cout << "Project version: " << project.child("version").text().as_double() << std::endl;
@@ -798,11 +793,11 @@
 
-

- If you need to get the document root of some - node, you can use the following function: +

+ If you need to get the document root of some node, you can use the following + function:

xml_node xml_node::root() const;
 
@@ -811,11 +806,10 @@ which is the root node of the document the node belongs to (unless the node is null, in which case null node is returned).

-

- While - pugixml supports complex XPath expressions, sometimes a simple path handling - facility is needed. There are two functions, for getting node path and for - converting path to a node: +

+ While pugixml supports complex XPath expressions, sometimes a simple path + handling facility is needed. There are two functions, for getting node path + and for converting path to a node:

string_t xml_node::path(char_t delimiter = '/') const;
 xml_node xml_node::first_element_by_path(const char_t* path, char_t delimiter = '/') const;
@@ -860,13 +854,12 @@
           is defined.
         

-

- pugixml does not record row/column information - for nodes upon parsing for efficiency reasons. However, if the node has not - changed in a significant way since parsing (the name/value are not changed, - and the node itself is the original one, i.e. it was not deleted from the - tree and re-added later), it is possible to get the offset from the beginning - of XML buffer: +

+ pugixml does not record row/column information for nodes upon parsing for + efficiency reasons. However, if the node has not changed in a significant + way since parsing (the name/value are not changed, and the node itself is + the original one, i.e. it was not deleted from the tree and re-added later), + it is possible to get the offset from the beginning of XML buffer:

ptrdiff_t xml_node::offset_debug() const;
 
@@ -890,7 +883,7 @@
-pugixml 1.4 manual | +pugixml 1.5 manual | Overview | Installation | Document: diff --git a/docs/manual/apiref.html b/docs/manual/apiref.html index 80e59e8..b9cbc77 100644 --- a/docs/manual/apiref.html +++ b/docs/manual/apiref.html @@ -4,15 +4,15 @@ API Reference - - + +
-pugixml 1.4 manual | +pugixml 1.5 manual | Overview | Installation | Document: @@ -28,7 +28,7 @@

This is the reference for all macros, types, enumerations, classes and functions @@ -130,6 +130,7 @@

  • node_doctype

    +
  • @@ -187,6 +188,7 @@
  • status_no_document_element

    +
  • @@ -222,6 +224,7 @@
  • encoding_latin1

    +
  • @@ -273,6 +276,7 @@
  • format_write_bom

    +
  • @@ -339,12 +343,14 @@
    @@ -512,12 +525,14 @@
  • xml_node();

    +
  • bool empty() const;
  • operator unspecified_bool_type() const;

    +
  • bool operator==(const xml_node& @@ -549,20 +564,24 @@ r) const;

    +
  • size_t hash_value() const;

    +
  • xml_node_type type() const;

    +
  • const char_t* name() const;
  • const char_t* value() const;

    +
  • xml_node parent() const; @@ -578,12 +597,14 @@
  • xml_node previous_sibling() const;

    +
  • xml_attribute first_attribute() const;
  • xml_attribute last_attribute() const;

    +
  • implementation-defined type children() const; @@ -595,6 +616,7 @@
  • implementation-defined type attributes() const;

    +
  • xml_node child(const char_t* @@ -626,6 +648,7 @@ xml_node find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const;

    +
  • const char_t* child_value() const; @@ -637,6 +660,7 @@
  • xml_text text() const;

    +
  • typedef xml_node_iterator @@ -647,6 +671,7 @@
  • iterator end() const;

    +
  • typedef xml_attribute_iterator @@ -657,9 +682,11 @@
  • attribute_iterator attributes_end() const;

    +
  • bool traverse(xml_tree_walker& walker);

    +
  • template <typename Predicate> xml_attribute @@ -679,6 +706,7 @@ pred) const;

    +
  • string_t path(char_t @@ -697,6 +725,7 @@
  • ptrdiff_t offset_debug() const;

    +
  • bool set_name(const char_t* @@ -706,6 +735,7 @@ bool set_value(const char_t* rhs);

    +
  • xml_attribute append_attribute(const char_t* @@ -724,6 +754,7 @@ xml_attribute insert_attribute_before(const char_t* name, const xml_attribute& attr);

    +
  • xml_node append_child(xml_node_type @@ -744,6 +775,7 @@ xml_node insert_child_before(xml_node_type type, const xml_node& node);

    +
  • xml_node append_child(const char_t* @@ -762,6 +794,7 @@ xml_node insert_child_before(const char_t* name, const xml_node& node);

    +
  • xml_attribute append_copy(const xml_attribute& proto); @@ -779,6 +812,7 @@ xml_attribute insert_copy_before(const xml_attribute& proto, const xml_attribute& attr);

    +
  • xml_node append_copy(const xml_node& @@ -797,6 +831,26 @@ xml_node insert_copy_before(const xml_node& proto, const xml_node& node);

    + +
  • +
  • + xml_node append_move(const xml_node& + moved); +
  • +
  • + xml_node prepend_move(const xml_node& + moved); +
  • +
  • + xml_node insert_move_after(const xml_node& + moved, + const xml_node& node); +
  • +
  • + xml_node insert_move_before(const xml_node& + moved, + const xml_node& node);

    +
  • bool remove_attribute(const xml_attribute& @@ -814,6 +868,7 @@ bool remove_child(const char_t* name);

    +
  • xml_parse_result append_buffer(const void* contents, @@ -823,6 +878,7 @@ encoding = encoding_auto);

    +
  • void print(xml_writer& writer, const @@ -863,17 +919,14 @@ 0) const;

    +
  • - xpath_node select_single_node(const char_t* - query, - xpath_variable_set* - variables = - 0) - const; + xpath_node select_node(const char_t* query, xpath_variable_set* variables + = 0) const;
  • - xpath_node select_single_node(const xpath_query& + xpath_node select_node(const xpath_query& query) const;
  • @@ -890,6 +943,7 @@ query) const;

    + @@ -901,6 +955,7 @@
  • ~xml_document();

    +
  • void reset(); @@ -909,6 +964,7 @@ void reset(const xml_document& proto);

    +
  • xml_parse_result load(std::istream& @@ -926,11 +982,16 @@ options = parse_default);

    +
  • - xml_parse_result load(const char_t* contents, unsigned - int options - = parse_default);

    + xml_parse_result load_string(const char_t* + contents, + unsigned int + options = + parse_default); +

    +
  • xml_parse_result load_file(const char* path, unsigned @@ -947,6 +1008,7 @@ parse_default, xml_encoding encoding = encoding_auto);

    +
  • xml_parse_result load_buffer(const void* contents, @@ -973,6 +1035,7 @@ parse_default, xml_encoding encoding = encoding_auto);

    +
  • bool save_file(const char* path, @@ -995,6 +1058,7 @@ encoding_auto) const;

    +
  • void save(std::ostream& stream, const @@ -1017,6 +1081,7 @@ format_default) const;

    +
  • void save(xml_writer& writer, const @@ -1028,9 +1093,11 @@ format_default, xml_encoding encoding = encoding_auto) const;

    +
  • xml_node document_element() const;

    +
  • @@ -1045,12 +1112,14 @@
  • xml_encoding encoding;

    +
  • operator bool() const;
  • const char* description() const;

    +
  • @@ -1060,6 +1129,7 @@
  • class xml_attribute_iterator

    +
  • class xml_tree_walker @@ -1075,9 +1145,11 @@
  • virtual bool end(xml_node& node);

    +
  • int depth() const;

    +
  • @@ -1089,9 +1161,11 @@
  • operator xml_text::unspecified_bool_type() const;

    +
  • const char_t* xml_text::get() const;

    +
  • const char_t* as_string(const char_t* @@ -1139,11 +1213,13 @@ 0) const;

    +
  • bool set(const char_t* rhs);

    +
  • bool set(int rhs); @@ -1167,6 +1243,7 @@ long long rhs);

    +
  • xml_text& @@ -1201,9 +1278,11 @@ long long rhs);

    +
  • xml_node data() const;

    +
  • @@ -1214,12 +1293,14 @@
    write(const void* data, size_t size) = 0;

    +
  • class xml_writer_file: public xml_writer
  • @@ -1230,6 +1311,7 @@
  • xml_writer_stream(std::wostream& stream);

    +
  • @@ -1247,6 +1329,7 @@
  • const char* description() const;

    +
  • @@ -1260,6 +1343,7 @@ variables = 0);


    +
  • bool evaluate_boolean(const xpath_node& @@ -1285,16 +1369,24 @@ xpath_node_set evaluate_node_set(const xpath_node& n) const; +
  • +
  • + xpath_node evaluate_node(const xpath_node& + n) + const;

    +
  • xpath_value_type return_type() const;

    +
  • const xpath_parse_result& result() const;
  • operator unspecified_bool_type() const;

    +
  • @@ -1307,9 +1399,11 @@
    what() const throw();

    +
  • const xpath_parse_result& result() const;

    +
  • @@ -1327,6 +1421,7 @@ xml_node& parent);


    +
  • xml_node node() const; @@ -1337,6 +1432,7 @@
  • xml_node parent() const;

    +
  • operator unspecified_bool_type() const; @@ -1351,6 +1447,7 @@ n) const;

    +
  • @@ -1367,6 +1464,7 @@ type = type_unsorted);


    +
  • typedef const @@ -1381,6 +1479,7 @@ const_iterator end() const;

    +
  • const xpath_node& operator[](size_t @@ -1392,11 +1491,13 @@
  • bool empty() const;

    +
  • xpath_node first() const;

    +
  • enum type_t @@ -1411,6 +1512,7 @@ void sort(bool reverse = false);

    +
  • @@ -1424,6 +1526,7 @@ xpath_value_type type() const;

    +
  • bool get_boolean() const; @@ -1436,6 +1539,7 @@
  • const xpath_node_set& get_node_set() const;

    +
  • bool set(bool value); @@ -1452,6 +1556,7 @@ bool set(const xpath_node_set& value);

    +
  • @@ -1463,6 +1568,7 @@
    add(const char_t* name, xpath_value_type type);

    +
  • bool set(const char_t* @@ -1483,6 +1589,7 @@ bool set(const char_t* name, const xpath_node_set& value);

    +
  • xpath_variable* @@ -1494,6 +1601,7 @@ name) const;

    +
  • @@ -1539,7 +1647,7 @@
    -pugixml 1.4 manual | +pugixml 1.5 manual | Overview | Installation | Document: diff --git a/docs/manual/changes.html b/docs/manual/changes.html index 58dc474..05891a7 100644 --- a/docs/manual/changes.html +++ b/docs/manual/changes.html @@ -4,15 +4,15 @@ Changelog - - + +
    -pugixml 1.4 manual | +pugixml 1.5 manual | Overview | Installation | Document: @@ -28,12 +28,110 @@
    -
    - - 27.02.2014 - - version 1.4 +
    + 27.11.2014 - version + 1.5 +
    +

    + Major release, featuring a lot of performance improvements and some new features. +

    +
      +
    • + Specification changes: +
        +
      1. + xml_document::load(const char_t*) was renamed to load_string; the + old method is still available and will be deprecated in a future + release +
      2. +
      3. + xml_node::select_single_node was renamed to select_node; the old + method is still available and will be deprecated in a future release. +
      4. +
      +
    • +
    • + New features: +
        +
      1. + Added xml_node::append_move and other functions for moving nodes + within a document +
      2. +
      3. + Added xpath_query::evaluate_node for evaluating queries with a single + node as a result +
      4. +
      +
    • +
    • + Performance improvements: +
        +
      1. + Optimized XML parsing (10-40% faster with clang/gcc, up to 10% faster + with MSVC) +
      2. +
      3. + Optimized memory consumption when copying nodes in the same document + (string contents is now shared) +
      4. +
      5. + Optimized node copying (10% faster for cross-document copies, 3x + faster for inter-document copies; also it now consumes a constant + amount of stack space) +
      6. +
      7. + Optimized node output (60% faster; also it now consumes a constant + amount of stack space) +
      8. +
      9. + Optimized XPath allocation (query evaluation now results in fewer + temporary allocations) +
      10. +
      11. + Optimized XPath sorting (node set sorting is 2-3x faster in some + cases) +
      12. +
      13. + Optimized XPath evaluation (XPathMark suite is 100x faster; some + commonly used queries are 3-4x faster) +
      14. +
      +
    • +
    • + Compatibility improvements: +
        +
      1. + Fixed xml_node::offset_debug for corner cases +
      2. +
      3. + Fixed undefined behavior while calling memcpy in some cases +
      4. +
      5. + Fixed MSVC 2015 compilation warnings +
      6. +
      7. + Fixed contrib/foreach.hpp for Boost 1.56.0 +
      8. +
      +
    • +
    • + Bug fixes +
        +
      1. + Adjusted comment output to avoid malformed documents if the comment + value contains "--" +
      2. +
      3. + Fix XPath sorting for documents that were constructed using append_buffer +
      4. +
      +
    • +
    +
    + 27.02.2014 - version + 1.4

    Major release, featuring various new features, bug fixes and compatibility @@ -113,10 +211,9 @@

    -
    - - 1.05.2012 - - version 1.2 +
    + 1.05.2012 - version + 1.2

    Major release, featuring header-only mode, various interface enhancements (i.e. @@ -208,10 +305,9 @@ -

    - - 1.11.2010 - - version 1.0 +
    + 1.11.2010 - version + 1.0

    Major release, featuring many XPath enhancements, wide character filename support, @@ -427,10 +523,9 @@ -

    - - 1.07.2010 - - version 0.9 +
    + 1.07.2010 - version + 0.9

    Major release, featuring extended and improved Unicode support, miscellaneous @@ -549,10 +644,9 @@ -

    - - 8.11.2009 - - version 0.5 +
    + 8.11.2009 - version + 0.5

    Major bugfix release. Changes: @@ -661,10 +755,9 @@ -

    - - 17.09.2009 - - version 0.42 +
    + 17.09.2009 - version + 0.42

    Maintenance release. Changes: @@ -707,10 +800,9 @@ -

    - - 8.02.2009 - - version 0.41 +
    + 8.02.2009 - version + 0.41

    Maintenance release. Changes: @@ -722,10 +814,9 @@ to output stream) -

    - - 18.01.2009 - - version 0.4 +
    + 18.01.2009 - version + 0.4

    Changes: @@ -801,10 +892,9 @@ -

    - - 31.10.2007 - - version 0.34 +
    + 31.10.2007 - version + 0.34

    Maintenance release. Changes: @@ -840,10 +930,9 @@ -

    - - 21.02.2007 - - version 0.3 +
    + 21.02.2007 - version + 0.3

    Refactored, reworked and improved version. Changes: @@ -902,10 +991,9 @@ -

    - - 6.11.2006 - - version 0.2 +
    + 6.11.2006 - version + 0.2

    First public release. Changes: @@ -937,10 +1025,9 @@ -

    - - 15.07.2006 - - version 0.1 +
    + 15.07.2006 - version + 0.1

    First private release for testing purposes @@ -956,7 +1043,7 @@


    -pugixml 1.4 manual | +pugixml 1.5 manual | Overview | Installation | Document: diff --git a/docs/manual/dom.html b/docs/manual/dom.html index 57d3ea0..3d7cd29 100644 --- a/docs/manual/dom.html +++ b/docs/manual/dom.html @@ -4,15 +4,15 @@ Document object model - - + +
    -pugixml 1.4 manual | +pugixml 1.5 manual | Overview | Installation | Document: @@ -28,20 +28,20 @@
    @@ -56,7 +56,7 @@

    The XML document is represented with a tree data structure. The root of the @@ -66,9 +66,9 @@ which correspond to C++ type xml_attribute, and some additional data (i.e. name).

    -

    - The tree nodes can be of one of the following - types (which together form the enumeration xml_node_type): +

    + The tree nodes can be of one of the following types (which together form + the enumeration xml_node_type):

    • @@ -81,6 +81,7 @@ several ways, which are covered below. There can be only one document node in the tree; document node does not have any XML representation.

      +
    • Element/tag node (node_element) - this @@ -188,7 +189,7 @@ (its parent should be the document). The example XML representation of a document type declaration node is as follows:
    -
    <!DOCTYPE greeting [ <!ELEMENT greeting (#PCDATA)> ]>
    +
    <!DOCTYPE greeting [ <!ELEMENT greeting (#PCDATA)> ]>
     

    Here the node has value "greeting [ <!ELEMENT @@ -208,6 +209,7 @@

    +

    <?xml version="1.0"?>
     <mesh name="mesh_root">
    @@ -235,7 +237,7 @@
     
     
    @@ -259,18 +261,21 @@ some operations on xml_node are only valid for certain node types. The classes are described below.

    -

    - xml_document is the owner of the entire - document structure; it is a non-copyable class. The interface of xml_document consists of loading functions - (see Loading document), saving functions (see Saving document) and the entire - interface of xml_node, which - allows for document inspection and/or modification. Note that while xml_document is a sub-class of xml_node, xml_node - is not a polymorphic type; the inheritance is present only to simplify usage. - Alternatively you can use the document_element - function to get the element node that's the immediate child of the document. +

    + xml_document is the owner + of the entire document structure; it is a non-copyable class. The interface + of xml_document consists + of loading functions (see Loading document), saving functions (see Saving document) + and the entire interface of xml_node, + which allows for document inspection and/or modification. Note that while + xml_document is a sub-class + of xml_node, xml_node is not a polymorphic type; the + inheritance is present only to simplify usage. Alternatively you can use + the document_element function + to get the element node that's the immediate child of the document.

    -

    - Default constructor of xml_document +

    + Default constructor of xml_document initializes the document to the tree with only a root node (document node). You can then populate it with data using either tree modification functions or loading functions; all loading functions destroy the previous tree with @@ -295,12 +300,12 @@ are destroyed.

    -

    - xml_node - is the handle to document node; it can point to any node in the document, - including the document node itself. There is a common interface for nodes - of all types; the actual node type can - be queried via the xml_node::type() method. Note that xml_node +

    + xml_node is the handle to + document node; it can point to any node in the document, including the document + node itself. There is a common interface for nodes of all types; the actual + node type can be queried via the xml_node::type() + method. Note that xml_node is only a handle to the actual node, not the node itself - you can have several xml_node handles pointing to the same underlying object. Destroying xml_node @@ -310,8 +315,8 @@ a pointer; you can safely pass or return xml_node objects by value without additional overhead.

    -

    - There is a special value of xml_node +

    + There is a special value of xml_node type, known as null node or empty node (such nodes have type node_null). It does not correspond to any node in any document, and thus resembles null pointer. However, all operations are defined on empty nodes; generally the operations don't do anything and @@ -321,40 +326,37 @@ have a parent, the first parent() call returns null node; the second parent() call then also returns null node, which makes error handling easier.

    -

    - xml_attribute - is the handle to an XML attribute; it has the same semantics as xml_node, i.e. there can be several xml_attribute handles pointing to the same - underlying object and there is a special null attribute value, which propagates - to function results. +

    + xml_attribute is the handle + to an XML attribute; it has the same semantics as xml_node, + i.e. there can be several xml_attribute + handles pointing to the same underlying object and there is a special null + attribute value, which propagates to function results.

    -

    - Both xml_node and xml_attribute - have the default constructor which initializes them to null objects. +

    + Both xml_node and xml_attribute have the default constructor + which initializes them to null objects.

    -

    - xml_node and xml_attribute - try to behave like pointers, that is, they can be compared with other objects - of the same type, making it possible to use them as keys in associative containers. - All handles to the same underlying object are equal, and any two handles - to different underlying objects are not equal. Null handles only compare - as equal to themselves. The result of relational comparison can not be reliably - determined from the order of nodes in file or in any other way. Do not use - relational comparison operators except for search optimization (i.e. associative - container keys). +

    + xml_node and xml_attribute try to behave like pointers, + that is, they can be compared with other objects of the same type, making + it possible to use them as keys in associative containers. All handles to + the same underlying object are equal, and any two handles to different underlying + objects are not equal. Null handles only compare as equal to themselves. + The result of relational comparison can not be reliably determined from the + order of nodes in file or in any other way. Do not use relational comparison + operators except for search optimization (i.e. associative container keys).

    -

    - If - you want to use xml_node +

    + If you want to use xml_node or xml_attribute objects as keys in hash-based associative containers, you can use the hash_value member functions. They return the hash values that are guaranteed to be the same for all handles to the same underlying object. The hash value for null handles is 0.

    -

    - Finally handles - can be implicitly cast to boolean-like objects, so that you can test if the - node/attribute is empty with the following code: if - (node) { ... +

    + Finally handles can be implicitly cast to boolean-like objects, so that you + can test if the node/attribute is empty with the following code: if (node) { ... } or if (!node) { ... } else { ... }. @@ -377,14 +379,14 @@

    There are two choices of interface and internal representation when configuring pugixml: you can either choose the UTF-8 (also called char) interface or UTF-16/32 (also called wchar_t) one. The choice is controlled via PUGIXML_WCHAR_MODE define; you can set it via pugiconfig.hpp or via preprocessor options, as - discussed in Additional configuration + discussed in Additional configuration options. If this define is set, the wchar_t interface is used; otherwise (by default) the char interface is used. The exact wide character encoding is assumed to be either UTF-16 or UTF-32 and @@ -416,13 +418,13 @@

    const wchar_t* xml_node::name() const;
     bool xml_node::set_name(const wchar_t* value);
     
    -

    - There is a special type, pugi::char_t, that is defined as the character - type and depends on the library configuration; it will be also used in the - documentation hereafter. There is also a type pugi::string_t, - which is defined as the STL string of the character type; it corresponds - to std::string in char mode and to std::wstring - in wchar_t mode. +

    + There is a special type, pugi::char_t, + that is defined as the character type and depends on the library configuration; + it will be also used in the documentation hereafter. There is also a type + pugi::string_t, which is defined as the STL string + of the character type; it corresponds to std::string + in char mode and to std::wstring in wchar_t mode.

    In addition to the interface, the internal implementation changes to store @@ -434,10 +436,9 @@ inconvenient to process and most of your XML data is non-ASCII, wchar_t mode is probably a better choice.

    -

    - There are cases when you'll have - to convert string data between UTF-8 and wchar_t encodings; the following - helper functions are provided for such purposes: +

    + There are cases when you'll have to convert string data between UTF-8 and + wchar_t encodings; the following helper functions are provided for such purposes:

    std::string as_utf8(const wchar_t* str);
     std::wstring as_wide(const char* str);
    @@ -484,7 +485,7 @@
     

    Almost all functions in pugixml have the following thread-safety guarantees: @@ -510,13 +511,13 @@

    The only exception is set_memory_management_functions; it modifies global variables and as such is not thread-safe. Its usage policy - has more restrictions, see Custom memory allocation/deallocation + has more restrictions, see Custom memory allocation/deallocation functions.

    With the exception of XPath, pugixml itself does not throw any exceptions. @@ -540,7 +541,7 @@

    pugixml requests the memory needed for document storage in big chunks, and @@ -549,22 +550,21 @@

    -

    - All - memory for tree structure, tree data and XPath objects is allocated via - globally specified functions, which default to malloc/free. You can set - your own allocation functions with set_memory_management function. The - function interfaces are the same as that of malloc/free: +

    + All memory for tree structure, tree data and XPath objects is allocated + via globally specified functions, which default to malloc/free. You can + set your own allocation functions with set_memory_management function. + The function interfaces are the same as that of malloc/free:

    typedef void* (*allocation_function)(size_t size);
     typedef void (*deallocation_function)(void* ptr);
     
    -

    - You can use the following accessor - functions to change or get current memory management functions: +

    + You can use the following accessor functions to change or get current memory + management functions:

    void set_memory_management_functions(allocation_function allocate, deallocation_function deallocate);
     allocation_function get_memory_allocation_function();
    @@ -589,6 +589,7 @@
               This is a simple example of custom memory management (samples/custom_memory_management.cpp):
             

    +

    void* custom_allocate(size_t size)
     {
    @@ -603,6 +604,7 @@
     

    +

    pugi::set_memory_management_functions(custom_allocate, custom_deallocate);
     
    @@ -617,7 +619,7 @@

    There are several important buffering optimizations in pugixml that rely @@ -629,7 +631,7 @@

    These constants can be tuned via configuration defines, as discussed in - Additional configuration + Additional configuration options; it is recommended to set them in pugiconfig.hpp.

      @@ -640,6 +642,7 @@ is 32 Kb; for some applications the size is too large (i.e. embedded systems with little heap space or applications that keep lots of XML documents in memory). A minimum size of 1 Kb is recommended.

      +
    • PUGIXML_MEMORY_OUTPUT_STACK @@ -649,6 +652,7 @@ using node output from threads with little stack space, decreasing this value can prevent stack overflows. A minimum size of 1 Kb is recommended.

      +
    • PUGIXML_MEMORY_XPATH_PAGE_SIZE @@ -663,7 +667,7 @@

    @@ -673,7 +677,7 @@

    When the document is loaded from file/buffer, unless an inplace loading - function is used (see Loading document from memory), a complete copy of character + function is used (see Loading document from memory), a complete copy of character stream is made; all names/values of nodes and attributes are allocated in this buffer. This buffer is allocated via a single large allocation and is only freed when document memory is reclaimed (i.e. if the xml_document object is destroyed or if another @@ -711,7 +715,7 @@


    -pugixml 1.4 manual | +pugixml 1.5 manual | Overview | Installation | Document: diff --git a/docs/manual/install.html b/docs/manual/install.html index 5675651..af662c1 100644 --- a/docs/manual/install.html +++ b/docs/manual/install.html @@ -4,15 +4,15 @@ Installation - - - + + +
    -pugixml 1.4 manual | +pugixml 1.5 manual | Overview | Installation | Document: @@ -28,48 +28,48 @@

    pugixml is distributed in source form. You can either download a source distribution - or checkout the Subversion repository. + or clone the Git repository.

    You can download the latest source distribution via one of the following links:

    -
    https://github.com/zeux/pugixml/releases/download/v1.4/pugixml-1.4.zip
    -https://github.com/zeux/pugixml/releases/download/v1.4/pugixml-1.4.tar.gz
    +
    https://github.com/zeux/pugixml/releases/download/v1.5/pugixml-1.5.zip
    +https://github.com/zeux/pugixml/releases/download/v1.5/pugixml-1.5.tar.gz
     

    The distribution contains library source, documentation (the manual you're @@ -80,56 +80,54 @@ line endings. Otherwise the files in both archives are identical.

    - If you need an older version, you can download it from the version + If you need an older version, you can download it from the version archive.

    - The Subversion repository is located at http://pugixml.googlecode.com/svn/. - There is a Subversion tag "release-{version}" for each version; - also there is the "latest" tag, which always points to the latest - stable release. + The Git repository is located at https://github.com/zeux/pugixml/. + There is a Git tag "v{version}" for each version; also there + is the "latest" tag, which always points to the latest stable + release.

    For example, to checkout the current version, you can use this command:

    -
    svn checkout http://pugixml.googlecode.com/svn/tags/release-1.4 pugixml
    -

    - To checkout the latest version, you can use this command: -

    -
    svn checkout http://pugixml.googlecode.com/svn/tags/latest pugixml
    +
    git clone https://github.com/zeux/pugixml
    +cd pugixml
    +git checkout v1.5
    +

    The repository contains library source, documentation, code examples and full unit test suite.

    - Use latest version tag if you want to automatically get new versions via - svn update. Use other tags if you want to switch to - new versions only explicitly (for example, using svn switch - command). Also please note that Subversion trunk contains the work-in-progress - version of the code; while this means that you can get new features and - bug fixes from trunk without waiting for a new release, this also means - that occasionally the code can be broken in some configurations. + Use latest version tag if you want to automatically get new versions. Use + other tags if you want to switch to new versions only explicitly. Also + please note that the master branch contains the work-in-progress version + of the code; while this means that you can get new features and bug fixes + from master without waiting for a new release, this also means that occasionally + the code can be broken in some configurations.

    - The Subversion repository is mirrored by a Git repository at https://github.com/zeux/pugixml. - The mirror is frequently updated and has the same structure in terms of - tags and contents as Subversion repository. + You can access the Git repository via Subversion using https://github.com/zeux/pugixml + URL. For example, to checkout the current version, you can use this command:

    +
    svn checkout https://github.com/zeux/pugixml/tags/v1.5 pugixml

    pugixml is distributed in source form without any pre-built binaries; you @@ -139,7 +137,7 @@ The complete pugixml source consists of three files - one source file, pugixml.cpp, and two header files, pugixml.hpp and pugiconfig.hpp. pugixml.hpp is the primary header which you need to include in order to use pugixml classes/functions; - pugiconfig.hpp is a supplementary configuration file (see Additional configuration + pugiconfig.hpp is a supplementary configuration file (see Additional configuration options). The rest of this guide assumes that pugixml.hpp is either in the current directory or in one of include directories of your projects, so that #include "pugixml.hpp" @@ -149,7 +147,7 @@

    @@ -194,7 +192,7 @@ are project files for Apple XCode3, Code::Blocks, Codelite, Microsoft Visual Studio 2005, 2008, 2010, and configuration scripts for CMake and premake4. You're welcome to submit project files/build scripts for other software; - see Feedback. + see Feedback.

    There are two projects for each version of Microsoft Visual Studio: one @@ -247,7 +245,7 @@

    -
    +

    It's possible to use pugixml in header-only mode. This means that all source @@ -324,7 +322,7 @@

    Note that it is safe to compile pugixml.cpp if PUGIXML_HEADER_ONLY is defined - so if you want to i.e. use header-only mode only in Release - configuration, you can include pugixml.cpp in your project (see Building pugixml as + configuration, you can include pugixml.cpp in your project (see Building pugixml as a part of another static library/executable), and conditionally enable header-only mode in pugiconfig.hpp, i.e.:

    @@ -336,7 +334,7 @@

    @@ -358,7 +356,7 @@ as character type) and UTF-16/32 style interface (the in-memory text encoding is assumed to be UTF-16/32, depending on wchar_t size, most functions use wchar_t - as character type). See Unicode interface for more details. + as character type). See Unicode interface for more details.

    PUGIXML_NO_XPATH define disables XPath. @@ -388,7 +386,7 @@ is used instead. For example, to specify fixed calling convention, you can define PUGIXML_FUNCTION to i.e. __fastcall. Another - example is DLL import/export attributes in MSVC (see Building pugixml as + example is DLL import/export attributes in MSVC (see Building pugixml as a standalone shared library).

    @@ -406,7 +404,7 @@ PUGIXML_MEMORY_PAGE_SIZE, PUGIXML_MEMORY_OUTPUT_STACK and PUGIXML_MEMORY_XPATH_PAGE_SIZE can be used to customize certain important sizes to optimize memory usage - for the application-specific patterns. For details see Memory consumption tuning. + for the application-specific patterns. For details see Memory consumption tuning.

    PUGIXML_HAS_LONG_LONG define enables @@ -422,7 +420,7 @@

    pugixml is written in standard-compliant C++ with some compiler-specific @@ -502,7 +500,7 @@


    -pugixml 1.4 manual | +pugixml 1.5 manual | Overview | Installation | Document: diff --git a/docs/manual/loading.html b/docs/manual/loading.html index e18cde6..d302f73 100644 --- a/docs/manual/loading.html +++ b/docs/manual/loading.html @@ -4,15 +4,15 @@ Loading document - - + +
    -pugixml 1.4 manual | +pugixml 1.5 manual | Overview | Installation | Document: @@ -28,16 +28,16 @@

    pugixml provides several functions for loading XML data from various places @@ -49,26 +49,25 @@ EOL handling or attribute value normalization) can impact parsing speed and thus can be disabled. However for vast majority of XML documents there is no performance difference between different parsing options. Parsing options also - control whether certain XML nodes are parsed; see Parsing options for + control whether certain XML nodes are parsed; see Parsing options for more information.

    - XML data is always converted to internal character format (see Unicode interface) + XML data is always converted to internal character format (see Unicode interface) before parsing. pugixml supports all popular Unicode encodings (UTF-8, UTF-16 (big and little endian), UTF-32 (big and little endian); UCS-2 is naturally supported since it's a strict subset of UTF-16) and handles all encoding conversions automatically. Unless explicit encoding is specified, loading functions perform automatic encoding detection based on first few characters of XML data, so in almost all cases you do not have to specify document encoding. Encoding - conversion is described in more detail in Encodings. + conversion is described in more detail in Encodings.

    -

    - The - most common source of XML data is files; pugixml provides dedicated functions +

    + The most common source of XML data is files; pugixml provides dedicated functions for loading an XML document from file:

    xml_parse_result xml_document::load_file(const char* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
    @@ -76,8 +75,8 @@
     

    These functions accept the file path as its first argument, and also two - optional arguments, which specify parsing options (see Parsing options) - and input data encoding (see Encodings). The path has the target + optional arguments, which specify parsing options (see Parsing options) + and input data encoding (see Encodings). The path has the target operating system format, so it can be a relative or absolute one, it should have the delimiters of the target system, it should have the exact case if the target file system is case-sensitive, etc. @@ -95,12 +94,13 @@ The result of the operation is returned in an xml_parse_result object; this object contains the operation status and the related information (i.e. last successfully parsed position in the input file, if parsing fails). - See Handling parsing errors for error handling details. + See Handling parsing errors for error handling details.

    This is an example of loading XML document from file (samples/load_file.cpp):

    +

    pugi::xml_document doc;
     
    @@ -113,19 +113,19 @@
     
    -

    - Sometimes XML data should be - loaded from some other source than a file, i.e. HTTP URL; also you may want - to load XML data from file using non-standard functions, i.e. to use your - virtual file system facilities or to load XML from gzip-compressed files. - All these scenarios require loading document from memory. First you should - prepare a contiguous memory block with all XML data; then you have to invoke - one of buffer loading functions. These functions will handle the necessary - encoding conversions, if any, and then will parse the data into the corresponding - XML tree. There are several buffer loading functions, which differ in the - behavior and thus in performance/memory usage: +

    + Sometimes XML data should be loaded from some other source than a file, i.e. + HTTP URL; also you may want to load XML data from file using non-standard + functions, i.e. to use your virtual file system facilities or to load XML + from gzip-compressed files. All these scenarios require loading document + from memory. First you should prepare a contiguous memory block with all + XML data; then you have to invoke one of buffer loading functions. These + functions will handle the necessary encoding conversions, if any, and then + will parse the data into the corresponding XML tree. There are several buffer + loading functions, which differ in the behavior and thus in performance/memory + usage:

    xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
     xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
    @@ -135,7 +135,7 @@
             All functions accept the buffer which is represented by a pointer to XML
             data, contents, and data
             size in bytes. Also there are two optional arguments, which specify parsing
    -        options (see Parsing options) and input data encoding (see Encodings).
    +        options (see  Parsing options) and input data encoding (see  Encodings).
             The buffer does not have to be zero-terminated.
           

    @@ -163,12 +163,11 @@ is the recommended function if you have to load the document from memory and performance is critical.

    -

    - There is also a simple helper function - for cases when you want to load the XML document from null-terminated character - string: +

    + There is also a simple helper function for cases when you want to load the + XML document from null-terminated character string:

    -
    xml_parse_result xml_document::load(const char_t* contents, unsigned int options = parse_default);
    +
    xml_parse_result xml_document::load_string(const char_t* contents, unsigned int options = parse_default);
     

    It is equivalent to calling load_buffer @@ -184,6 +183,7 @@ (samples/load_memory.cpp):

    +

    const char source[] = "<mesh name='sphere'><bounds>0 0 1 1</bounds></mesh>";
     size_t size = sizeof(source);
    @@ -191,57 +191,61 @@
     

    +

    -
    // You can use load_buffer to load document from immutable memory block:
    -pugi::xml_parse_result result = doc.load_buffer(source, size);
    +
    // You can use load_buffer to load document from immutable memory block:
    +pugi::xml_parse_result result = doc.load_buffer(source, size);
     

    +

    -
    // You can use load_buffer_inplace to load document from mutable memory block; the block's lifetime must exceed that of document
    -char* buffer = new char[size];
    +
    // You can use load_buffer_inplace to load document from mutable memory block; the block's lifetime must exceed that of document
    +char* buffer = new char[size];
     memcpy(buffer, source, size);
     
    -// The block can be allocated by any method; the block is modified during parsing
    -pugi::xml_parse_result result = doc.load_buffer_inplace(buffer, size);
    +// The block can be allocated by any method; the block is modified during parsing
    +pugi::xml_parse_result result = doc.load_buffer_inplace(buffer, size);
     
    -// You have to destroy the block yourself after the document is no longer used
    -delete[] buffer;
    +// You have to destroy the block yourself after the document is no longer used
    +delete[] buffer;
     

    +

    -
    // You can use load_buffer_inplace_own to load document from mutable memory block and to pass the ownership of this block
    -// The block has to be allocated via pugixml allocation function - using i.e. operator new here is incorrect
    -char* buffer = static_cast<char*>(pugi::get_memory_allocation_function()(size));
    +
    // You can use load_buffer_inplace_own to load document from mutable memory block and to pass the ownership of this block
    +// The block has to be allocated via pugixml allocation function - using i.e. operator new here is incorrect
    +char* buffer = static_cast<char*>(pugi::get_memory_allocation_function()(size));
     memcpy(buffer, source, size);
     
    -// The block will be deleted by the document
    -pugi::xml_parse_result result = doc.load_buffer_inplace_own(buffer, size);
    +// The block will be deleted by the document
    +pugi::xml_parse_result result = doc.load_buffer_inplace_own(buffer, size);
     

    +

    -
    // You can use load to load document from null-terminated strings, for example literals:
    -pugi::xml_parse_result result = doc.load("<mesh name='sphere'><bounds>0 0 1 1</bounds></mesh>");
    +
    // You can use load to load document from null-terminated strings, for example literals:
    +pugi::xml_parse_result result = doc.load_string("<mesh name='sphere'><bounds>0 0 1 1</bounds></mesh>");
     

    -

    - To enhance interoperability, pugixml - provides functions for loading document from any object which implements - C++ std::istream interface. This allows you to load - documents from any standard C++ stream (i.e. file stream) or any third-party - compliant implementation (i.e. Boost Iostreams). There are two functions, - one works with narrow character streams, another handles wide character ones: +

    + To enhance interoperability, pugixml provides functions for loading document + from any object which implements C++ std::istream + interface. This allows you to load documents from any standard C++ stream + (i.e. file stream) or any third-party compliant implementation (i.e. Boost + Iostreams). There are two functions, one works with narrow character streams, + another handles wide character ones:

    xml_parse_result xml_document::load(std::istream& stream, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
     xml_parse_result xml_document::load(std::wistream& stream, unsigned int options = parse_default);
    @@ -271,6 +275,7 @@
             the sample code for more complex examples involving wide streams and locales:
           

    +

    std::ifstream stream("weekly-utf-8.xml");
     pugi::xml_parse_result result = doc.load(stream);
    @@ -280,14 +285,12 @@
     
    -

    - All document loading functions return the - parsing result via xml_parse_result - object. It contains parsing status, the offset of last successfully parsed - character from the beginning of the source stream, and the encoding of the - source stream: +

    + All document loading functions return the parsing result via xml_parse_result object. It contains parsing + status, the offset of last successfully parsed character from the beginning + of the source stream, and the encoding of the source stream:

    struct xml_parse_result
     {
    @@ -299,9 +302,8 @@
         const char* description() const;
     };
     
    -

    - Parsing - status is represented as the xml_parse_status +

    + Parsing status is represented as the xml_parse_status enumeration and can be one of the following:

      @@ -309,6 +311,7 @@ status_ok means that no error was encountered during parsing; the source stream represents the valid XML document which was fully parsed and converted to a tree.

      +
    • status_file_not_found is only @@ -327,6 +330,7 @@
    • status_internal_error means that something went horribly wrong; currently this error does not occur

      +
    • status_unrecognized_tag means @@ -373,12 +377,14 @@ indicates an empty or invalid document
    -

    - description() member function can be used to convert - parsing status to a string; the returned message is always in English, so - you'll have to write your own function if you need a localized string. However - please note that the exact messages returned by description() function may change from version to version, - so any complex status handling should be based on status +

    + description() + member function can be used to convert parsing status to a string; the returned + message is always in English, so you'll have to write your own function if + you need a localized string. However please note that the exact messages + returned by description() + function may change from version to version, so any complex status handling + should be based on status value. Note that description() returns a char string even in PUGIXML_WCHAR_MODE; you'll have to call as_wide to get the wchar_t string. @@ -393,18 +399,16 @@ attribute attr will contain the string value>some data</node>.

    -

    - In addition to the status code, parsing - result has an offset member, - which contains the offset of last successfully parsed character if parsing - failed because of an error in source data; otherwise offset - is 0. For parsing efficiency reasons, pugixml does not track the current - line during parsing; this offset is in units of pugi::char_t - (bytes for character mode, wide characters for wide character mode). Many - text editors support 'Go To Position' feature - you can use it to locate - the exact error position. Alternatively, if you're loading the document from - memory, you can display the error chunk along with the error description - (see the example code below). +

    + In addition to the status code, parsing result has an offset + member, which contains the offset of last successfully parsed character if + parsing failed because of an error in source data; otherwise offset is 0. For parsing efficiency reasons, + pugixml does not track the current line during parsing; this offset is in + units of pugi::char_t (bytes for character + mode, wide characters for wide character mode). Many text editors support + 'Go To Position' feature - you can use it to locate the exact error position. + Alternatively, if you're loading the document from memory, you can display + the error chunk along with the error description (see the example code below).

    @@ -417,17 +421,16 @@ track the error position.

    -

    - Parsing result also has an encoding member, which can be used to check - that the source data encoding was correctly guessed. It is equal to the exact - encoding used during parsing (i.e. with the exact endianness); see Encodings for - more information. -

    -

    - Parsing result object can be implicitly - converted to bool; if you do - not want to handle parsing errors thoroughly, you can just check the return - value of load functions as if it was a bool: +

    + Parsing result also has an encoding + member, which can be used to check that the source data encoding was correctly + guessed. It is equal to the exact encoding used during parsing (i.e. with + the exact endianness); see Encodings for more information. +

    +

    + Parsing result object can be implicitly converted to bool; + if you do not want to handle parsing errors thoroughly, you can just check + the return value of load functions as if it was a bool: if (doc.load_file("file.xml")) { ... } else { ... }.

    @@ -435,9 +438,10 @@ This is an example of handling loading errors (samples/load_error_handling.cpp):

    +

    pugi::xml_document doc;
    -pugi::xml_parse_result result = doc.load(source);
    +pugi::xml_parse_result result = doc.load_string(source);
     
     if (result)
         std::cout << "XML [" << source << "] parsed without errors, attr value: [" << doc.child("node").attribute("attr").value() << "]\n\n";
    @@ -453,7 +457,7 @@
     

    All document loading functions accept the optional parameter options. This is a bitmask that customizes @@ -485,12 +489,14 @@ document declaration (node with type node_declaration) is to be put in DOM tree. If this flag is off, it is not put in the tree, but is still parsed and checked for correctness. This flag is off by default.

    +

  • parse_doctype determines if XML document type declaration (node with type node_doctype) is to be put in DOM tree. If this flag is off, it is not put in the tree, but is still parsed and checked for correctness. This flag is off by default.

    +
  • parse_pi determines if processing instructions @@ -498,18 +504,21 @@ in DOM tree. If this flag is off, they are not put in the tree, but are still parsed and checked for correctness. Note that <?xml ...?> (document declaration) is not considered to be a PI. This flag is off by default.

    +
  • parse_comments determines if comments (nodes with type node_comment) are to be put in DOM tree. If this flag is off, they are not put in the tree, but are still parsed and checked for correctness. This flag is off by default.

    +
  • parse_cdata determines if CDATA sections (nodes with type node_cdata) are to be put in DOM tree. If this flag is off, they are not put in the tree, but are still parsed and checked for correctness. This flag is on by default.

    +
  • parse_trim_pcdata determines if leading @@ -518,6 +527,7 @@ often the application only cares about the non-whitespace contents so it's easier to trim whitespace from text during parsing. This flag is off by default.

    +
  • parse_ws_pcdata determines if PCDATA @@ -536,6 +546,7 @@ one child when parse_ws_pcdata is not set. This flag is off by default.

    +
  • parse_ws_pcdata_single determines @@ -554,6 +565,7 @@ This flag has no effect if parse_ws_pcdata is enabled. This flag is off by default.

    +
  • parse_fragment determines if document @@ -598,6 +610,7 @@ ones). If character/entity reference can not be expanded, it is left as is, so you can do additional processing later. Reference expansion is performed on attribute values and PCDATA content. This flag is on by default.

    +
  • parse_eol determines if EOL handling (that @@ -607,6 +620,7 @@ be performed on input data (that is, comments contents, PCDATA/CDATA contents and attribute values). This flag is on by default.

    +
  • parse_wconv_attribute determines @@ -617,6 +631,7 @@ is set, i.e. \r\n is converted to a single space. This flag is on by default.

    +
  • parse_wnorm_attribute determines @@ -656,6 +671,7 @@ so theoretically it is the fastest mode. However, as mentioned above, in practice parse_default is usually equally fast.

    +
  • parse_default is the default set of flags, @@ -665,6 +681,7 @@ in attribute values and performing EOL handling. Note, that PCDATA sections consisting only of whitespace characters are not parsed (by default) for performance reasons.

    +
  • parse_full is the set of flags which adds @@ -681,23 +698,24 @@ This is an example of using different parsing options (samples/load_options.cpp):

    +

    const char* source = "<!--comment--><node>&lt;</node>";
     
    -// Parsing with default options; note that comment node is not added to the tree, and entity reference &lt; is expanded
    -doc.load(source);
    +// Parsing with default options; note that comment node is not added to the tree, and entity reference &lt; is expanded
    +doc.load_string(source);
     std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n";
     
    -// Parsing with additional parse_comments option; comment node is now added to the tree
    -doc.load(source, pugi::parse_default | pugi::parse_comments);
    +// Parsing with additional parse_comments option; comment node is now added to the tree
    +doc.load_string(source, pugi::parse_default | pugi::parse_comments);
     std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n";
     
    -// Parsing with additional parse_comments option and without the (default) parse_escapes option; &lt; is not expanded
    -doc.load(source, (pugi::parse_default | pugi::parse_comments) & ~pugi::parse_escapes);
    +// Parsing with additional parse_comments option and without the (default) parse_escapes option; &lt; is not expanded
    +doc.load_string(source, (pugi::parse_default | pugi::parse_comments) & ~pugi::parse_escapes);
     std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n";
     
    -// Parsing with minimal option mask; comment node is not added to the tree, and &lt; is not expanded
    -doc.load(source, pugi::parse_minimal);
    +// Parsing with minimal option mask; comment node is not added to the tree, and &lt; is not expanded
    +doc.load_string(source, pugi::parse_minimal);
     std::cout << "First node value: [" << doc.first_child().value() << "], node child value: [" << doc.child_value("node") << "]\n";
     

    @@ -705,15 +723,14 @@

  • -

    - pugixml supports all popular Unicode encodings - (UTF-8, UTF-16 (big and little endian), UTF-32 (big and little endian); UCS-2 - is naturally supported since it's a strict subset of UTF-16) and handles - all encoding conversions. Most loading functions accept the optional parameter - encoding. This is a value - of enumeration type xml_encoding, +

    + pugixml supports all popular Unicode encodings (UTF-8, UTF-16 (big and little + endian), UTF-32 (big and little endian); UCS-2 is naturally supported since + it's a strict subset of UTF-16) and handles all encoding conversions. Most + loading functions accept the optional parameter encoding. + This is a value of enumeration type xml_encoding, that can have the following values:

      @@ -751,6 +768,7 @@
    • Otherwise encoding is assumed to be UTF-8.

      +
    @@ -822,7 +840,7 @@

    pugixml is not fully W3C conformant - it can load any valid XML document, @@ -879,7 +897,7 @@


    -pugixml 1.4 manual | +pugixml 1.5 manual | Overview | Installation | Document: diff --git a/docs/manual/modify.html b/docs/manual/modify.html index 05b0fbe..5e44d90 100644 --- a/docs/manual/modify.html +++ b/docs/manual/modify.html @@ -4,15 +4,15 @@ Modifying document data - - + +
    -pugixml 1.4 manual | +pugixml 1.5 manual | Overview | Installation | Document: @@ -28,16 +28,17 @@

    The document in pugixml is fully mutable: you can completely change the document @@ -61,12 +62,11 @@

    -

    - 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 +

    + 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 a name or value, node_element and node_declaration nodes always have a name but never have a value, node_pcdata, @@ -98,31 +98,31 @@ 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");
    +// 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");
    +// 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;
    +// 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: +

    + 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);
    @@ -177,8 +177,8 @@
               including string conversions.
             

    -

    - For convenience, all set_value +

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

    xml_attribute& xml_attribute::operator=(const char_t* rhs);
    @@ -199,19 +199,20 @@
             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");
    +// 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);
    +// 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;
    +// we can also use assignment operators for more concise code
    +attr = true;
     std::cout << "final attribute value: " << attr.value() << std::endl;
     

    @@ -219,11 +220,10 @@

    -

    - Nodes - and attributes do not exist without a document tree, so you can't create +

    + Nodes and attributes do not exist without a 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:

    @@ -317,19 +317,20 @@ 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");
    +
    // add node with some name
    +pugi::xml_node node = doc.append_child("node");
     
    -// add description node with text child
    -pugi::xml_node descr = node.append_child("description");
    +// add description node with text child
    +pugi::xml_node descr = node.append_child("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("param", descr);
    +// add param node before the description
    +pugi::xml_node param = node.insert_child_before("param", descr);
     
    -// add attributes to param node
    -param.append_attribute("name") = "version";
    +// 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";
     
    @@ -338,11 +339,10 @@
    -

    - If - you do not want your document to contain some node or attribute, you can +

    + 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);
    @@ -394,17 +394,18 @@
             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");
    +
    // 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");
    +// 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");
    +// we can also remove nodes/attributes by handles
    +pugi::xml_attribute id = param.attribute("name");
     param.remove_attribute(id);
     

    @@ -412,7 +413,7 @@

    pugixml provides a special class, xml_text, @@ -421,8 +422,8 @@ documentation for accessing document data; this section describes the modification interface of xml_text.

    -

    - Once you have an xml_text +

    + Once you have an xml_text object, you can set the text contents using the following function:

    bool xml_text::set(const char_t* rhs);
    @@ -439,9 +440,9 @@
             an element node, this function creates the PCDATA child node if necessary
             (i.e. if the element node does not have a PCDATA/CDATA child already).
           

    -

    - In addition to a string function, several - functions are provided for handling text with numbers and booleans as contents: +

    + In addition to a string function, several functions are provided for handling + text with numbers and booleans as contents:

    bool xml_text::set(int rhs);
     bool xml_text::set(unsigned int rhs);
    @@ -457,8 +458,8 @@
             functions. You can refer to documentation
             for the attribute functions for details.
           

    -

    - For convenience, all set +

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

    xml_text& xml_text::operator=(const char_t* rhs);
    @@ -480,29 +481,30 @@
             object to modify text contents (samples/text.cpp):
           

    +

    -
    // change project version
    -project.child("version").text() = 1.2;
    +
    // change project version
    +project.child("version").text() = 1.2;
     
    -// add description element and set the contents
    -// note that we do not have to explicitly add the node_pcdata child
    -project.append_child("description").text().set("a test project");
    +// add description element and set the contents
    +// note that we do not have to explicitly add the node_pcdata child
    +project.append_child("description").text().set("a test project");
     

    -

    - 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 without a 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: +

    + 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 + without a 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::prepend_copy(const xml_attribute& proto);
    @@ -559,6 +561,7 @@
             node cloning and usage of other document modification functions:
           

    +

    bool load_preprocess(pugi::xml_document& doc, const char* path);
     
    @@ -570,23 +573,23 @@
             {
                 pugi::xml_node include = child;
     
    -            // load new preprocessed document (note: ideally this should handle relative paths)
    -            const char* path = include.value();
    +            // 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);
    +            // 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())
    +            // 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();
    +            // remove the include node and move to the next child
    +            child = child.next_sibling();
     
                 node.remove_child(include);
             }
    @@ -603,8 +606,8 @@
     
     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?>
    -
    +    pugi::xml_parse_result result = doc.load_file(path, pugi::parse_default | pugi::parse_pi); // for <?include?>
    +    
         return result ? preprocess(doc) : false;
     }
     
    @@ -613,13 +616,64 @@
    +

    + Sometimes instead of cloning a node you need to move an existing node to + a different position in a tree. This can be accomplished by copying the node + and removing the original; however, this is expensive since it results in + a lot of extra operations. For moving nodes within the same document tree, + you can use of the following functions instead: +

    +
    xml_node xml_node::append_move(const xml_node& moved);
    +xml_node xml_node::prepend_move(const xml_node& moved);
    +xml_node xml_node::insert_move_after(const xml_node& moved, const xml_node& node);
    +xml_node xml_node::insert_move_before(const xml_node& moved, const xml_node& node);
    +
    +

    + These functions mirror the structure of append_copy, + prepend_copy, insert_copy_before and insert_copy_after + - they take the handle to the moved object and move it to the appropriate + place with all attributes and/or child nodes. The functions return the handle + to the resulting object (which is the same as the moved object), or null + handle on failure. +

    - pugixml provides several ways to assemble - an XML document from other XML documents. Assuming there is a set of document - fragments, represented as in-memory buffers, the implementation choices are - as follows: + 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 moving + functions: +

    +
      +
    • + Moving null handles results in operation failure; +
    • +
    • + Moving is only possible for nodes that belong to the same document; attempting + to move nodes between documents will fail. +
    • +
    • + insert_move_after and + insert_move_before functions + fail if the moved node is the same as the node + argument (this operation would be a no-op otherwise). +
    • +
    • + It is impossible to move a subtree to a child of some node inside this + subtree, i.e. node.append_move(node.parent().parent()); + will fail. +
    • +
    +
    +
    + +

    + pugixml provides several ways to assemble an XML document from other XML + documents. Assuming there is a set of document fragments, represented as + in-memory buffers, the implementation choices are as follows:

    • Use a temporary document to parse the data from a string, then clone @@ -668,10 +722,10 @@ - the input buffer is a byte buffer, with size in bytes; the buffer is not modified and can be freed after the function returns.

      -

      - Since append_buffer - needs to append child nodes to the current node, it only works if the current - node is either document or element node. Calling append_buffer +

      + Since append_buffer needs + to append child nodes to the current node, it only works if the current node + is either document or element node. Calling append_buffer on a node with any other type results in an error with status_append_invalid_root status.

      @@ -687,7 +741,7 @@
      -pugixml 1.4 manual | +pugixml 1.5 manual | Overview | Installation | Document: diff --git a/docs/manual/saving.html b/docs/manual/saving.html index 2c05a7b..7157d84 100644 --- a/docs/manual/saving.html +++ b/docs/manual/saving.html @@ -4,15 +4,15 @@ Saving document - - + +
      -pugixml 1.4 manual | +pugixml 1.5 manual | Overview | Installation | Document: @@ -28,16 +28,16 @@

      Often after creating a new document or loading the existing one and processing @@ -46,8 +46,8 @@ include debug printing, serialization via network or other text-oriented medium, etc. pugixml provides several functions to output any subtree of the document to a file, stream or another generic transport interface; these functions allow - to customize the output format (see Output options), and also perform - necessary encoding conversions (see Encodings). This section documents + to customize the output format (see Output options), and also perform + necessary encoding conversions (see Encodings). This section documents the relevant functionality.

      @@ -68,20 +68,19 @@

      -

      - If - you want to save the whole document to a file, you can use one of the following - functions: +

      + If you want to save the whole document to a file, you can use one of the + following functions:

      bool xml_document::save_file(const char* path, const char_t* indent = "\t", unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
       bool xml_document::save_file(const wchar_t* path, const char_t* indent = "\t", unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
       

      These functions accept file path as its first argument, and also three optional - arguments, which specify indentation and other output options (see Output options) - and output data encoding (see Encodings). The path has the target + arguments, which specify indentation and other output options (see Output options) + and output data encoding (see Encodings). The path has the target operating system format, so it can be a relative or absolute one, it should have the delimiters of the target system, it should have the exact case if the target file system is case-sensitive, etc. @@ -93,39 +92,38 @@ a special file opening function if it is provided by the runtime library or converts the path to UTF-8 and uses the system file opening function.

      -

      - save_file - opens the target file for writing, outputs the requested header (by default - a document declaration is output, unless the document already has one), and - then saves the document contents. If the file could not be opened, the function - returns false. Calling save_file is equivalent to creating an - xml_writer_file object with - FILE* +

      + save_file opens the target + file for writing, outputs the requested header (by default a document declaration + is output, unless the document already has one), and then saves the document + contents. If the file could not be opened, the function returns false. Calling save_file + is equivalent to creating an xml_writer_file + object with FILE* handle as the only constructor argument and then calling save; - see Saving document via writer interface for writer interface details. + see Saving document via writer interface for writer interface details.

      This is a simple example of saving XML document to file (samples/save_file.cpp):

      +

      -
      // save document to file
      -std::cout << "Saving result: " << doc.save_file("save_file_output.xml") << std::endl;
      +
      // save document to file
      +std::cout << "Saving result: " << doc.save_file("save_file_output.xml") << std::endl;
       

      -

      - To enhance interoperability pugixml - provides functions for saving document to any object which implements C++ - std::ostream interface. This allows you to save - documents to any standard C++ stream (i.e. file stream) or any third-party - compliant implementation (i.e. Boost Iostreams). Most notably, this allows - for easy debug output, since you can use std::cout +

      + To enhance interoperability pugixml provides functions for saving document + to any object which implements C++ std::ostream + interface. This allows you to save documents to any standard C++ stream (i.e. + file stream) or any third-party compliant implementation (i.e. Boost Iostreams). + Most notably, this allows for easy debug output, since you can use std::cout stream as saving target. There are two functions, one works with narrow character streams, another handles wide character ones:

      @@ -145,19 +143,20 @@ you with the ability to save documents to non-Unicode encodings, i.e. you can save Shift-JIS encoded data if you set the correct locale.

      -

      - Calling save - with stream target is equivalent to creating an xml_writer_stream - object with stream as the only constructor argument and then calling save; see Saving document via writer interface for writer +

      + Calling save with stream + target is equivalent to creating an xml_writer_stream + object with stream as the only constructor argument and then calling save; see Saving document via writer interface for writer interface details.

      This is a simple example of saving XML document to standard output (samples/save_stream.cpp):

      +

      -
      // save document to standard output
      -std::cout << "Document:\n";
      +
      // save document to standard output
      +std::cout << "Document:\n";
       doc.save(std::cout);
       

      @@ -165,11 +164,10 @@

      -

      - All - of the above saving functions are implemented in terms of writer interface. +

      + All of the above saving functions are implemented in terms of writer interface. This is a simple interface with a single function, which is called several times during output process with chunks of document data as input:

      @@ -205,6 +203,7 @@ read the sample code for more complex examples:

      +

      struct xml_string_writer: pugi::xml_writer
       {
      @@ -221,11 +220,10 @@
       
      -

      - While - the previously described functions save the whole document to the destination, +

      + While the previously described functions save the whole document to the destination, it is easy to save a single subtree. The following functions are provided:

      void xml_node::print(std::ostream& os, const char_t* indent = "\t", unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const;
      @@ -248,21 +246,22 @@
               illustrates the difference:
             

      +

      -
      // get a test document
      -pugi::xml_document doc;
      -doc.load("<foo bar='baz'><call>hey</call></foo>");
      +
      // get a test document
      +pugi::xml_document doc;
      +doc.load_string("<foo bar='baz'><call>hey</call></foo>");
       
      -// print document to standard output (prints <?xml version="1.0"?><foo bar="baz"><call>hey</call></foo>)
      -doc.save(std::cout, "", pugi::format_raw);
      +// print document to standard output (prints <?xml version="1.0"?><foo bar="baz"><call>hey</call></foo>)
      +doc.save(std::cout, "", pugi::format_raw);
       std::cout << std::endl;
       
      -// print document to standard output as a regular node (prints <foo bar="baz"><call>hey</call></foo>)
      -doc.print(std::cout, "", pugi::format_raw);
      +// print document to standard output as a regular node (prints <foo bar="baz"><call>hey</call></foo>)
      +doc.print(std::cout, "", pugi::format_raw);
       std::cout << std::endl;
       
      -// print a subtree to standard output (prints <call>hey</call>)
      -doc.child("foo").child("call").print(std::cout, "", pugi::format_raw);
      +// print a subtree to standard output (prints <call>hey</call>)
      +doc.child("foo").child("call").print(std::cout, "", pugi::format_raw);
       std::cout << std::endl;
       

      @@ -270,7 +269,7 @@

      All saving functions accept the optional parameter flags. @@ -302,6 +301,7 @@ node's depth relative to the output subtree. This flag has no effect if format_raw is enabled. This flag is on by default.

      +

    • format_raw switches between formatted and @@ -312,6 +312,7 @@ with parse_ws_pcdata flag, to preserve the original document formatting as much as possible. This flag is off by default.

      +
    • format_no_escapes disables output @@ -337,6 +338,7 @@ the document contents. Enabling this flag disables this declaration. This flag has no effect in xml_node::print functions: they never output the default declaration. This flag is off by default.

      +
    • format_write_bom enables Byte Order @@ -372,43 +374,44 @@ This is an example that shows the outputs of different output options (samples/save_options.cpp):

      +

      -
      // get a test document
      -pugi::xml_document doc;
      -doc.load("<foo bar='baz'><call>hey</call></foo>");
      +
      // get a test document
      +pugi::xml_document doc;
      +doc.load_string("<foo bar='baz'><call>hey</call></foo>");
       
      -// default options; prints
      -// <?xml version="1.0"?>
      -// <foo bar="baz">
      -//         <call>hey</call>
      -// </foo>
      -doc.save(std::cout);
      +// default options; prints
      +// <?xml version="1.0"?>
      +// <foo bar="baz">
      +//         <call>hey</call>
      +// </foo>
      +doc.save(std::cout);
       std::cout << std::endl;
       
      -// default options with custom indentation string; prints
      -// <?xml version="1.0"?>
      -// <foo bar="baz">
      -// --<call>hey</call>
      -// </foo>
      -doc.save(std::cout, "--");
      +// default options with custom indentation string; prints
      +// <?xml version="1.0"?>
      +// <foo bar="baz">
      +// --<call>hey</call>
      +// </foo>
      +doc.save(std::cout, "--");
       std::cout << std::endl;
       
      -// default options without indentation; prints
      -// <?xml version="1.0"?>
      -// <foo bar="baz">
      -// <call>hey</call>
      -// </foo>
      -doc.save(std::cout, "\t", pugi::format_default & ~pugi::format_indent); // can also pass "" instead of indentation string for the same effect
      -std::cout << std::endl;
      +// default options without indentation; prints
      +// <?xml version="1.0"?>
      +// <foo bar="baz">
      +// <call>hey</call>
      +// </foo>
      +doc.save(std::cout, "\t", pugi::format_default & ~pugi::format_indent); // can also pass "" instead of indentation string for the same effect
      +std::cout << std::endl;
       
      -// raw output; prints
      -// <?xml version="1.0"?><foo bar="baz"><call>hey</call></foo>
      -doc.save(std::cout, "\t", pugi::format_raw);
      +// raw output; prints
      +// <?xml version="1.0"?><foo bar="baz"><call>hey</call></foo>
      +doc.save(std::cout, "\t", pugi::format_raw);
       std::cout << std::endl << std::endl;
       
      -// raw output without declaration; prints
      -// <foo bar="baz"><call>hey</call></foo>
      -doc.save(std::cout, "\t", pugi::format_raw | pugi::format_no_declaration);
      +// raw output without declaration; prints
      +// <foo bar="baz"><call>hey</call></foo>
      +doc.save(std::cout, "\t", pugi::format_raw | pugi::format_no_declaration);
       std::cout << std::endl;
       

      @@ -416,7 +419,7 @@

    • pugixml supports all popular Unicode encodings (UTF-8, UTF-16 (big and little @@ -424,7 +427,7 @@ it's a strict subset of UTF-16) and handles all encoding conversions during output. The output encoding is set via the encoding parameter of saving functions, which is of type xml_encoding. - The possible values for the encoding are documented in Encodings; + The possible values for the encoding are documented in Encodings; the only flag that has a different meaning is encoding_auto.

      @@ -457,7 +460,7 @@

      When you are saving the document using xml_document::save() or xml_document::save_file(), a default XML document declaration is @@ -490,22 +493,23 @@ This is an example that shows how to create a custom declaration node (samples/save_declaration.cpp):

      +

      -
      // get a test document
      -pugi::xml_document doc;
      -doc.load("<foo bar='baz'><call>hey</call></foo>");
      +
      // get a test document
      +pugi::xml_document doc;
      +doc.load_string("<foo bar='baz'><call>hey</call></foo>");
       
      -// add a custom declaration node
      -pugi::xml_node decl = doc.prepend_child(pugi::node_declaration);
      +// add a custom declaration node
      +pugi::xml_node decl = doc.prepend_child(pugi::node_declaration);
       decl.append_attribute("version") = "1.0";
       decl.append_attribute("encoding") = "UTF-8";
       decl.append_attribute("standalone") = "no";
       
      -// <?xml version="1.0" encoding="UTF-8" standalone="no"?> 
      -// <foo bar="baz">
      -//         <call>hey</call>
      -// </foo>
      -doc.save(std::cout);
      +// <?xml version="1.0" encoding="UTF-8" standalone="no"?> 
      +// <foo bar="baz">
      +//         <call>hey</call>
      +// </foo>
      +doc.save(std::cout);
       std::cout << std::endl;
       

      @@ -522,7 +526,7 @@


      -pugixml 1.4 manual | +pugixml 1.5 manual | Overview | Installation | Document: diff --git a/docs/manual/toc.html b/docs/manual/toc.html index 3bedd68..b36f757 100644 --- a/docs/manual/toc.html +++ b/docs/manual/toc.html @@ -4,14 +4,14 @@ Table of Contents - - + +
      -pugixml 1.4 manual | +pugixml 1.5 manual | Overview | Installation | Document: @@ -27,112 +27,113 @@
      -
      Overview
      +
      Overview
      -
      Introduction
      -
      Feedback
      -
      Acknowledgments
      -
      License
      +
      Introduction
      +
      Feedback
      +
      Acknowledgments
      +
      License
      -
      Installation
      +
      Installation
      -
      Getting pugixml
      +
      Getting pugixml
      -
      Source distributions
      -
      Subversion repository
      -
      Git repository
      +
      Source distributions
      +
      Git repository
      +
      Subversion repository
      -
      Building pugixml
      +
      Building pugixml
      -
      Building pugixml as +
      Building pugixml as a part of another static library/executable
      -
      Building pugixml as +
      Building pugixml as a standalone static library
      -
      Building pugixml as +
      Building pugixml as a standalone shared library
      -
      Using - pugixml in header-only mode
      -
      Additional configuration +
      Using pugixml in header-only + mode
      +
      Additional configuration options
      -
      Portability
      +
      Portability
      -
      Document object model
      +
      Document object model
      -
      Tree structure
      -
      C++ interface
      -
      Unicode interface
      -
      Thread-safety guarantees
      -
      Exception guarantees
      -
      Memory management
      +
      Tree structure
      +
      C++ interface
      +
      Unicode interface
      +
      Thread-safety guarantees
      +
      Exception guarantees
      +
      Memory management
      -
      Custom memory allocation/deallocation +
      Custom memory allocation/deallocation functions
      -
      Memory consumption tuning
      -
      Document memory management +
      Memory consumption tuning
      +
      Document memory management internals
      -
      Loading document
      +
      Loading document
      -
      Loading document from file
      -
      Loading document from memory
      -
      Loading document from C++ IOstreams
      -
      Handling parsing errors
      -
      Parsing options
      -
      Encodings
      -
      Conformance to W3C specification
      +
      Loading document from file
      +
      Loading document from memory
      +
      Loading document from C++ IOstreams
      +
      Handling parsing errors
      +
      Parsing options
      +
      Encodings
      +
      Conformance to W3C specification
      -
      Accessing document data
      +
      Accessing document data
      -
      Basic traversal functions
      -
      Getting node data
      -
      Getting attribute data
      -
      Contents-based traversal functions
      -
      Range-based for-loop support
      -
      Traversing node/attribute lists +
      Basic traversal functions
      +
      Getting node data
      +
      Getting attribute data
      +
      Contents-based traversal functions
      +
      Range-based for-loop support
      +
      Traversing node/attribute lists via iterators
      -
      Recursive traversal with xml_tree_walker
      -
      Searching for nodes/attributes +
      Recursive traversal with xml_tree_walker
      +
      Searching for nodes/attributes with predicates
      -
      Working with text contents
      -
      Miscellaneous functions
      +
      Working with text contents
      +
      Miscellaneous functions
      -
      Modifying document data
      +
      Modifying document data
      -
      Setting node data
      -
      Setting attribute data
      -
      Adding nodes/attributes
      -
      Removing nodes/attributes
      -
      Working with text contents
      -
      Cloning nodes/attributes
      -
      Assembling document from fragments
      +
      Setting node data
      +
      Setting attribute data
      +
      Adding nodes/attributes
      +
      Removing nodes/attributes
      +
      Working with text contents
      +
      Cloning nodes/attributes
      +
      Moving nodes
      +
      Assembling document from fragments
      -
      Saving document
      +
      Saving document
      -
      Saving document to a file
      -
      Saving document to C++ IOstreams
      -
      Saving document via writer interface
      -
      Saving a single subtree
      -
      Output options
      -
      Encodings
      -
      Customizing document declaration
      +
      Saving document to a file
      +
      Saving document to C++ IOstreams
      +
      Saving document via writer interface
      +
      Saving a single subtree
      +
      Output options
      +
      Encodings
      +
      Customizing document declaration
      -
      XPath
      +
      XPath
      -
      XPath types
      -
      Selecting nodes via XPath expression
      -
      Using query objects
      -
      Using variables
      -
      Error handling
      -
      Conformance to W3C specification
      +
      XPath types
      +
      Selecting nodes via XPath expression
      +
      Using query objects
      +
      Using variables
      +
      Error handling
      +
      Conformance to W3C specification
      -
      Changelog
      -
      API Reference
      -
      Table of Contents
      +
      Changelog
      +
      API Reference
      +
      Table of Contents
      @@ -145,7 +146,7 @@
      -pugixml 1.4 manual | +pugixml 1.5 manual | Overview | Installation | Document: diff --git a/docs/manual/xpath.html b/docs/manual/xpath.html index e2290e5..7194283 100644 --- a/docs/manual/xpath.html +++ b/docs/manual/xpath.html @@ -4,15 +4,15 @@ XPath - - + +
      -pugixml 1.4 manual | +pugixml 1.5 manual | Overview | Installation | Document: @@ -28,15 +28,15 @@

      If the task at hand is to select a subset of document nodes that match some @@ -48,7 +48,7 @@ for these cases. pugixml implements an almost complete subset of XPath 1.0. Because of differences in document object model and some performance implications, there are minor violations of the official specifications, which can be found - in Conformance to W3C specification. The rest of this section describes the interface for XPath + in Conformance to W3C specification. The rest of this section describes the interface for XPath functionality. Please note that if you wish to learn to use XPath language, you have to look for other tutorials or manuals; for example, you can read W3Schools XPath tutorial, @@ -58,12 +58,11 @@

      -

      - Each - XPath expression can have one of the following types: boolean, number, string - or node set. Boolean type corresponds to bool +

      + Each XPath expression can have one of the following types: boolean, number, + string or node set. Boolean type corresponds to bool type, number type corresponds to double type, string type corresponds to either std::string or std::wstring, depending on whether wide @@ -73,11 +72,11 @@ xpath_type_number, xpath_type_string or xpath_type_node_set, accordingly.

      -

      - Because an XPath node can be either a node or an - attribute, there is a special type, xpath_node, - which is a discriminated union of these types. A value of this type contains - two node handles, one of xml_node +

      + Because an XPath node can be either a node or an attribute, there is a special + type, xpath_node, which is + a discriminated union of these types. A value of this type contains two node + handles, one of xml_node type, and another one of xml_attribute type; at most one of them can be non-null. The accessors to get these handles are available: @@ -102,33 +101,30 @@ handle. For null nodes, parent returns null handle.

      -

      - Like - node and attribute handles, XPath node handles can be implicitly cast to - boolean-like object to check if it is a null node, and also can be compared +

      + Like node and attribute handles, XPath node handles can be implicitly cast + to boolean-like object to check if it is a null node, and also can be compared for equality with each other.

      -

      - You can also create XPath nodes with one of - the three constructors: the default constructor, the constructor that takes - node argument, and the constructor that takes attribute and node arguments - (in which case the attribute must belong to the attribute list of the node). - The constructor from xml_node - is implicit, so you can usually pass xml_node - to functions that expect xpath_node. - Apart from that you usually don't need to create your own XPath node objects, - since they are returned to you via selection functions. -

      -

      - XPath expressions operate not on single nodes, - but instead on node sets. A node set is a collection of nodes, which can - be optionally ordered in either a forward document order or a reverse one. - Document order is defined in XPath specification; an XPath node is before - another node in document order if it appears before it in XML representation - of the corresponding document. -

      -

      - Node sets are represented by xpath_node_set +

      + You can also create XPath nodes with one of the three constructors: the default + constructor, the constructor that takes node argument, and the constructor + that takes attribute and node arguments (in which case the attribute must + belong to the attribute list of the node). The constructor from xml_node is implicit, so you can usually + pass xml_node to functions + that expect xpath_node. Apart + from that you usually don't need to create your own XPath node objects, since + they are returned to you via selection functions. +

      +

      + XPath expressions operate not on single nodes, but instead on node sets. + A node set is a collection of nodes, which can be optionally ordered in either + a forward document order or a reverse one. Document order is defined in XPath + specification; an XPath node is before another node in document order if + it appears before it in XML representation of the corresponding document. +

      +

      + Node sets are represented by xpath_node_set object, which has an interface that resembles one of sequential random-access containers. It has an iterator type along with usual begin/past-the-end iterator accessors: @@ -137,9 +133,8 @@ const_iterator xpath_node_set::begin() const; const_iterator xpath_node_set::end() const; -

      - And it also can be iterated via indices, just - like std::vector: +

      + And it also can be iterated via indices, just like std::vector:

      const xpath_node& xpath_node_set::operator[](size_t index) const;
       size_t xpath_node_set::size() const;
      @@ -152,9 +147,9 @@
               set size results in undefined behavior. You can use both iterator-based and
               index-based access for iteration, however the iterator-based one can be faster.
             

      -

      - The order of iteration depends on the order of - nodes inside the set; the order can be queried via the following function: +

      + The order of iteration depends on the order of nodes inside the set; the + order can be queried via the following function:

      enum xpath_node_set::type_t {type_unsorted, type_sorted, type_sorted_reverse};
       type_t xpath_node_set::type() const;
      @@ -178,10 +173,9 @@
               will return type_sorted or
               type_sorted_reverse.
             

      -

      - Often the actual iteration is not needed; - instead, only the first element in document order is required. For this, - a special accessor is provided: +

      + Often the actual iteration is not needed; instead, only the first element + in document order is required. For this, a special accessor is provided:

      xpath_node xpath_node_set::first() const;
       
      @@ -193,11 +187,10 @@ the complexity does - if the set is sorted, the complexity is constant, otherwise it is linear in the number of elements or worse.

      -

      - While in the majority of cases the node - set is returned by XPath functions, sometimes there is a need to manually - construct a node set. For such cases, a constructor is provided which takes - an iterator range (const_iterator +

      + While in the majority of cases the node set is returned by XPath functions, + sometimes there is a need to manually construct a node set. For such cases, + a constructor is provided which takes an iterator range (const_iterator is a typedef for const xpath_node*), and an optional type:

      xpath_node_set::xpath_node_set(const_iterator begin, const_iterator end, type_t type = type_unsorted);
      @@ -212,41 +205,40 @@
       
      -

      - If - you want to select nodes that match some XPath expression, you can do it - with the following functions: +

      + If you want to select nodes that match some XPath expression, you can do + it with the following functions:

      -
      xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables = 0) const;
      +
      xpath_node xml_node::select_node(const char_t* query, xpath_variable_set* variables = 0) const;
       xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables = 0) const;
       

      select_nodes function compiles the expression and then executes it with the node as a context node, and - returns the resulting node set. select_single_node + returns the resulting node set. select_node returns only the first node in document order from the result, and is equivalent to calling select_nodes(query).first(). If the XPath expression does not match anything, or the node handle is null, select_nodes returns an empty - set, and select_single_node - returns null XPath node. + set, and select_node returns + null XPath node.

      If exception handling is not disabled, both functions throw xpath_exception if the query can not be compiled or if it returns a value with type other - than node set; see Error handling for details. + than node set; see Error handling for details.

      -

      - While - compiling expressions is fast, the compilation time can introduce a significant - overhead if the same expression is used many times on small subtrees. If - you're doing many similar queries, consider compiling them into query objects - (see Using query objects for further reference). Once you get a compiled query - object, you can pass it to select functions instead of an expression string: +

      + While compiling expressions is fast, the compilation time can introduce a + significant overhead if the same expression is used many times on small subtrees. + If you're doing many similar queries, consider compiling them into query + objects (see Using query objects for further reference). Once you get a compiled + query object, you can pass it to select functions instead of an expression + string:

      -
      xpath_node xml_node::select_single_node(const xpath_query& query) const;
      +
      xpath_node xml_node::select_node(const xpath_query& query) const;
       xpath_node_set xml_node::select_nodes(const xpath_query& query) const;
       

      @@ -257,6 +249,7 @@ This is an example of selecting nodes using XPath expressions (samples/xpath_select.cpp):

      +

      pugi::xpath_node_set tools = doc.select_nodes("/Profile/Tools/Tool[@AllowRemote='true' and @DeriveCaptionFrom='lastparam']");
       
      @@ -268,7 +261,7 @@
           std::cout << node.node().attribute("Filename").value() << "\n";
       }
       
      -pugi::xpath_node build_tool = doc.select_single_node("//Tool[contains(Description, 'build system')]");
      +pugi::xpath_node build_tool = doc.select_node("//Tool[contains(Description, 'build system')]");
       
       if (build_tool)
           std::cout << "Build tool: " << build_tool.node().attribute("Filename").value() << "\n";
      @@ -278,10 +271,10 @@
       
      -

      - When you call select_nodes +

      + When you call select_nodes with an expression string as an argument, a query object is created behind the scenes. A query object represents a compiled XPath expression. Query objects can be needed in the following circumstances: @@ -307,30 +300,29 @@ operator and store pointers to xpath_query in the container.

      -

      - You can create a query object with the constructor - that takes XPath expression as an argument: +

      + You can create a query object with the constructor that takes XPath expression + as an argument:

      explicit xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables = 0);
       
      -

      - The expression is compiled and the - compiled representation is stored in the new query object. If compilation - fails, xpath_exception is thrown if - exception handling is not disabled (see Error handling for details). - After the query is created, you can query the type of the evaluation result - using the following function: +

      + The expression is compiled and the compiled representation is stored in the + new query object. If compilation fails, xpath_exception + is thrown if exception handling is not disabled (see Error handling for + details). After the query is created, you can query the type of the evaluation + result using the following function:

      xpath_value_type xpath_query::return_type() const;
       
      -

      - You - can evaluate the query using one of the following functions: +

      + You can evaluate the query using one of the following functions:

      bool xpath_query::evaluate_boolean(const xpath_node& n) const;
       double xpath_query::evaluate_number(const xpath_node& n) const;
       string_t xpath_query::evaluate_string(const xpath_node& n) const;
       xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const;
      +xpath_node xpath_query::evaluate_node(const xpath_node& n) const;
       

      All functions take the context node as an argument, compute the expression @@ -339,8 +331,9 @@ value, but no type other than node set can be converted to node set. Because of this, evaluate_boolean, evaluate_number and evaluate_string always return a result, - but evaluate_node_set results - in an error if the return type is not node set (see Error handling). + but evaluate_node_set and + evaluate_node result in an + error if the return type is not node set (see Error handling).

      @@ -349,12 +342,12 @@

      Calling node.select_nodes("query") - is equivalent to calling xpath_query("query").evaluate_node_set(node). + is equivalent to calling xpath_query("query").evaluate_node_set(node). Calling node.select_node("query") is equivalent to calling xpath_query("query").evaluate_node(node).

      -

      - Note that evaluate_string function returns the STL - string; as such, it's not available in PUGIXML_NO_STL +

      + Note that evaluate_string + function returns the STL string; as such, it's not available in PUGIXML_NO_STL mode and also usually allocates memory. There is another string evaluation function:

      @@ -386,20 +379,21 @@ This is an example of using query objects (samples/xpath_query.cpp):

      +

      -
      // Select nodes via compiled query
      -pugi::xpath_query query_remote_tools("/Profile/Tools/Tool[@AllowRemote='true']");
      +
      // Select nodes via compiled query
      +pugi::xpath_query query_remote_tools("/Profile/Tools/Tool[@AllowRemote='true']");
       
       pugi::xpath_node_set tools = query_remote_tools.evaluate_node_set(doc);
       std::cout << "Remote tool: ";
       tools[2].node().print(std::cout);
       
      -// Evaluate numbers via compiled query
      -pugi::xpath_query query_timeouts("sum(//Tool/@Timeout)");
      +// Evaluate numbers via compiled query
      +pugi::xpath_query query_timeouts("sum(//Tool/@Timeout)");
       std::cout << query_timeouts.evaluate_number(doc) << std::endl;
       
      -// Evaluate strings via compiled query for different context nodes
      -pugi::xpath_query query_name_valid("string-length(substring-before(@Filename, '_')) > 0 and @OutputFileMasks");
      +// Evaluate strings via compiled query for different context nodes
      +pugi::xpath_query query_name_valid("string-length(substring-before(@Filename, '_')) > 0 and @OutputFileMasks");
       pugi::xpath_query query_name("concat(substring-before(@Filename, '_'), ' produces ', @OutputFileMasks)");
       
       for (pugi::xml_node tool = doc.first_element_by_path("Profile/Tools/Tool"); tool; tool = tool.next_sibling())
      @@ -414,7 +408,7 @@
       

      XPath queries may contain references to variables; this is useful if you @@ -426,10 +420,10 @@ Variable references have the form $name; in order to use them, you have to provide a variable set, which includes all variables present in the query with correct types. This set is passed to xpath_query - constructor or to select_nodes/select_single_node functions: + constructor or to select_nodes/select_node functions:

      explicit xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables = 0);
      -xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables = 0) const;
      +xpath_node xml_node::select_node(const char_t* query, xpath_variable_set* variables = 0) const;
       xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables = 0) const;
       

      @@ -447,13 +441,12 @@ that the lifetime of the set exceeds that of query object.

      -

      - Variable sets correspond to xpath_variable_set type, which is essentially - a variable container. +

      + Variable sets correspond to xpath_variable_set + type, which is essentially a variable container.

      -

      - You can add new variables with the - following function: +

      + You can add new variables with the following function:

      xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type);
       
      @@ -470,9 +463,8 @@ 0 for numbers, false for booleans, empty string for strings and empty set for node sets.

      -

      - You can get the existing variables - with the following functions: +

      + You can get the existing variables with the following functions:

      xpath_variable* xpath_variable_set::get(const char_t* name);
       const xpath_variable* xpath_variable_set::get(const char_t* name) const;
      @@ -481,14 +473,13 @@
               The functions return the variable handle, or null pointer if the variable
               with the specified name is not found.
             

      -

      - Additionally, there are the helper - functions for setting the variable value by name; they try to add the variable - with the corresponding type, if it does not exist, and to set the value. - If the variable with the same name but with different type is already present, - they return false; they also - return false on allocation failure. - Note that these functions do not perform any type conversions. +

      + Additionally, there are the helper functions for setting the variable value + by name; they try to add the variable with the corresponding type, if it + does not exist, and to set the value. If the variable with the same name + but with different type is already present, they return false; + they also return false on allocation + failure. Note that these functions do not perform any type conversions.

      bool xpath_variable_set::set(const char_t* name, bool value);
       bool xpath_variable_set::set(const char_t* name, double value);
      @@ -499,15 +490,14 @@
               The variable values are copied to the internal variable storage, so you can
               modify or destroy them after the functions return.
             

      -

      - If setting variables by name is not efficient - enough, or if you have to inspect variable information or get variable values, - you can use variable handles. A variable corresponds to the xpath_variable type, and a variable handle - is simply a pointer to xpath_variable. +

      + If setting variables by name is not efficient enough, or if you have to inspect + variable information or get variable values, you can use variable handles. + A variable corresponds to the xpath_variable + type, and a variable handle is simply a pointer to xpath_variable.

      -

      - In - order to get variable information, you can use one of the following functions: +

      + In order to get variable information, you can use one of the following functions:

      const char_t* xpath_variable::name() const;
       xpath_value_type xpath_variable::type() const;
      @@ -516,9 +506,8 @@
               Note that each variable has a distinct type which is specified upon variable
               creation and can not be changed later.
             

      -

      - In - order to get variable value, you should use one of the following functions, +

      + In order to get variable value, you should use one of the following functions, depending on the variable type:

      bool xpath_variable::get_boolean() const;
      @@ -531,9 +520,9 @@
               are performed; if the type mismatch occurs, a dummy value is returned (false for booleans, NaN
               for numbers, empty string for strings and empty set for node sets).
             

      -

      - In order to set variable value, you should - use one of the following functions, depending on the variable type: +

      + In order to set variable value, you should use one of the following functions, + depending on the variable type:

      bool xpath_variable::set(bool value);
       bool xpath_variable::set(double value);
      @@ -550,9 +539,10 @@
               This is an example of using variables in XPath queries (samples/xpath_variables.cpp):
             

      +

      -
      // Select nodes via compiled query
      -pugi::xpath_variable_set vars;
      +
      // Select nodes via compiled query
      +pugi::xpath_variable_set vars;
       vars.add("remote", pugi::xpath_type_boolean);
       
       pugi::xpath_query query_remote_tools("/Profile/Tools/Tool[@AllowRemote = string($remote)]", &vars);
      @@ -569,8 +559,8 @@
       std::cout << "Local tool: ";
       tools_local[0].node().print(std::cout);
       
      -// You can pass the context directly to select_nodes/select_single_node
      -pugi::xpath_node_set tools_local_imm = doc.select_nodes("/Profile/Tools/Tool[@AllowRemote = string($remote)]", &vars);
      +// You can pass the context directly to select_nodes/select_node
      +pugi::xpath_node_set tools_local_imm = doc.select_nodes("/Profile/Tools/Tool[@AllowRemote = string($remote)]", &vars);
       
       std::cout << "Local tool imm: ";
       tools_local_imm[0].node().print(std::cout);
      @@ -580,7 +570,7 @@
       
       

      There are two different mechanisms for error handling in XPath implementation; @@ -588,23 +578,21 @@ is controlled with PUGIXML_NO_EXCEPTIONS define).

      -

      - By default, XPath functions throw xpath_exception object in case of errors; - additionally, in the event any memory allocation fails, an std::bad_alloc - exception is thrown. Also xpath_exception - is thrown if the query is evaluated to a node set, but the return type is - not node set. If the query constructor succeeds (i.e. no exception is thrown), - the query object is valid. Otherwise you can get the error details via one - of the following functions: +

      + By default, XPath functions throw xpath_exception + object in case of errors; additionally, in the event any memory allocation + fails, an std::bad_alloc exception is thrown. Also xpath_exception is thrown if the query + is evaluated to a node set, but the return type is not node set. If the query + constructor succeeds (i.e. no exception is thrown), the query object is valid. + Otherwise you can get the error details via one of the following functions:

      virtual const char* xpath_exception::what() const throw();
       const xpath_parse_result& xpath_exception::result() const;
       
      -

      - If - exceptions are disabled, then in the event of parsing failure the query is - initialized to invalid state; you can test if the query object is valid by - using it in a boolean expression: if +

      + If exceptions are disabled, then in the event of parsing failure the query + is initialized to invalid state; you can test if the query object is valid + by using it in a boolean expression: if (query) { ... }. Additionally, you can get parsing result via the result() accessor: @@ -617,9 +605,8 @@ a query as a node set results in an empty node set if the return type is not node set.

      -

      - The information about parsing result is - returned via xpath_parse_result +

      + The information about parsing result is returned via xpath_parse_result object. It contains parsing status and the offset of last successfully parsed character from the beginning of the source stream:

      @@ -632,39 +619,39 @@ const char* description() const; };
      -

      - Parsing result is represented as - the error message; it is either a null pointer, in case there is no error, - or the error message in the form of ASCII zero-terminated string. +

      + Parsing result is represented as the error message; it is either a null pointer, + in case there is no error, or the error message in the form of ASCII zero-terminated + string.

      -

      - description() member function can be used to get the - error message; it never returns the null pointer, so you can safely use +

      + description() + member function can be used to get the error message; it never returns the + null pointer, so you can safely use description() even if query parsing succeeded. Note that description() - even if query parsing succeeded. Note that description() returns a char - string even in PUGIXML_WCHAR_MODE; - you'll have to call as_wide to get the wchar_t string. + returns a char string even in + PUGIXML_WCHAR_MODE; you'll + have to call as_wide to get the wchar_t string.

      -

      - In addition to the error message, - parsing result has an offset +

      + In addition to the error message, parsing result has an offset member, which contains the offset of last successfully parsed character. This offset is in units of pugi::char_t (bytes for character mode, wide characters for wide character mode).

      -

      - Parsing result object can be implicitly - converted to bool like this: - if (result) { ... } +

      + Parsing result object can be implicitly converted to bool + like this: if (result) { ... } else { ... }.

      This is an example of XPath error handling (samples/xpath_error.cpp):

      +

      -
      // Exception is thrown for incorrect query syntax
      -try
      +
      // Exception is thrown for incorrect query syntax
      +try
       {
           doc.select_nodes("//nodes[#true()]");
       }
      @@ -673,8 +660,8 @@
           std::cout << "Select failed: " << e.what() << std::endl;
       }
       
      -// Exception is thrown for incorrect query semantics
      -try
      +// Exception is thrown for incorrect query semantics
      +try
       {
           doc.select_nodes("(123)/next");
       }
      @@ -683,8 +670,8 @@
           std::cout << "Select failed: " << e.what() << std::endl;
       }
       
      -// Exception is thrown for query with incorrect return type
      -try
      +// Exception is thrown for query with incorrect return type
      +try
       {
           doc.select_nodes("123");
       }
      @@ -698,7 +685,7 @@
       
       

      Because of the differences in document object models, performance considerations @@ -745,7 +732,7 @@


      -pugixml 1.4 manual | +pugixml 1.5 manual | Overview | Installation | Document: diff --git a/docs/quickstart.html b/docs/quickstart.html index 8f8fa4e..c702852 100644 --- a/docs/quickstart.html +++ b/docs/quickstart.html @@ -1,31 +1,31 @@ -pugixml 1.4 +pugixml 1.5 - +

      No documentation is perfect, neither is this one. If you encounter a description - that is unclear, please file an issue as described in Feedback. Also if + that is unclear, please file an issue as described in Feedback. Also if you can spare the time for a full proof-reading, including spelling and grammar, that would be great! Please send me an e-mail; as a token of appreciation, your name will be included into the corresponding @@ -69,14 +69,14 @@

      pugixml is distributed in source form. You can download a source distribution via one of the following links:

      -
      https://github.com/zeux/pugixml/releases/download/v1.4/pugixml-1.4.zip
      -https://github.com/zeux/pugixml/releases/download/v1.4/pugixml-1.4.tar.gz
      +
      https://github.com/zeux/pugixml/releases/download/v1.5/pugixml-1.5.zip
      +https://github.com/zeux/pugixml/releases/download/v1.5/pugixml-1.5.tar.gz
       

      The distribution contains library source, documentation (the guide you're @@ -109,7 +109,7 @@

      pugixml stores XML data in DOM-like way: the entire XML document (both document @@ -226,7 +226,7 @@

      pugixml provides several functions for loading XML data from various places @@ -250,6 +250,7 @@ This is an example of loading XML document from file (samples/load_file.cpp):

      +

      pugi::xml_document doc;
       
      @@ -281,9 +282,10 @@
               This is an example of handling loading errors (samples/load_error_handling.cpp):
             

      +

      pugi::xml_document doc;
      -pugi::xml_parse_result result = doc.load(source);
      +pugi::xml_parse_result result = doc.load_string(source);
       
       if (result)
           std::cout << "XML [" << source << "] parsed without errors, attr value: [" << doc.child("node").attribute("attr").value() << "]\n\n";
      @@ -322,6 +324,7 @@
               read the sample code for more examples:
             

      +

      const char source[] = "<mesh name='sphere'><bounds>0 0 1 1</bounds></mesh>";
       size_t size = sizeof(source);
      @@ -329,16 +332,17 @@
       

      +

      -
      // You can use load_buffer_inplace to load document from mutable memory block; the block's lifetime must exceed that of document
      -char* buffer = new char[size];
      +
      // You can use load_buffer_inplace to load document from mutable memory block; the block's lifetime must exceed that of document
      +char* buffer = new char[size];
       memcpy(buffer, source, size);
       
      -// The block can be allocated by any method; the block is modified during parsing
      -pugi::xml_parse_result result = doc.load_buffer_inplace(buffer, size);
      +// The block can be allocated by any method; the block is modified during parsing
      +pugi::xml_parse_result result = doc.load_buffer_inplace(buffer, size);
       
      -// You have to destroy the block yourself after the document is no longer used
      -delete[] buffer;
      +// You have to destroy the block yourself after the document is no longer used
      +delete[] buffer;
       

      @@ -348,6 +352,7 @@ the sample code for more complex examples involving wide streams and locales:

      +

      std::ifstream stream("weekly-utf-8.xml");
       pugi::xml_parse_result result = doc.load(stream);
      @@ -357,7 +362,7 @@
       

      pugixml features an extensive interface for getting various types of data @@ -394,6 +399,7 @@ This is an example of using these functions (samples/traverse_base.cpp):

      +

      for (pugi::xml_node tool = tools.child("Tool"); tool; tool = tool.next_sibling("Tool"))
       {
      @@ -414,6 +420,7 @@
               functions (samples/traverse_base.cpp):
             

      +

      std::cout << "Tool for *.dae generation: " << tools.find_child_by_attribute("Tool", "OutputFileMasks", "*.dae").attribute("Filename").value() << "\n";
       
      @@ -438,6 +445,7 @@
               Here is an example of using iterators for document traversal (samples/traverse_iter.cpp):
             

      +

      for (pugi::xml_node_iterator it = tools.begin(); it != tools.end(); ++it)
       {
      @@ -466,6 +474,7 @@
               (samples/traverse_rangefor.cpp):
             

      +

      for (pugi::xml_node tool: tools.children("Tool"))
       {
      @@ -499,22 +508,24 @@
               This is an example of traversing tree hierarchy with xml_tree_walker (samples/traverse_walker.cpp):
             

      +

      struct simple_walker: pugi::xml_tree_walker
       {
           virtual bool for_each(pugi::xml_node& node)
           {
      -        for (int i = 0; i < depth(); ++i) std::cout << "  "; // indentation
      -
      +        for (int i = 0; i < depth(); ++i) std::cout << "  "; // indentation
      +
               std::cout << node_types[node.type()] << ": name='" << node.name() << "', value='" << node.value() << "'\n";
       
      -        return true; // continue traversal
      -    }
      +        return true; // continue traversal
      +    }
       };
       

      +

      simple_walker walker;
       doc.traverse(walker);
      @@ -528,6 +539,7 @@
               examples:
             

      +

      pugi::xpath_node_set tools = doc.select_nodes("/Profile/Tools/Tool[@AllowRemote='true' and @DeriveCaptionFrom='lastparam']");
       
      @@ -539,7 +551,7 @@
           std::cout << node.node().attribute("Filename").value() << "\n";
       }
       
      -pugi::xpath_node build_tool = doc.select_single_node("//Tool[contains(Description, 'build system')]");
      +pugi::xpath_node build_tool = doc.select_node("//Tool[contains(Description, 'build system')]");
       
       if (build_tool)
           std::cout << "Build tool: " << build_tool.node().attribute("Filename").value() << "\n";
      @@ -559,7 +571,7 @@
       

      The document in pugixml is fully mutable: you can completely change the document @@ -590,36 +602,38 @@ example of setting node/attribute name and value (samples/modify_base.cpp):

      +

      pugi::xml_node node = doc.child("node");
       
      -// change node name
      -std::cout << node.set_name("notnode");
      +// 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");
      +// 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;
      +// 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;
       

      +

      pugi::xml_attribute attr = node.attribute("id");
       
      -// change attribute name/value
      -std::cout << attr.set_name("key") << ", " << attr.set_value("345");
      +// 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);
      +// 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;
      +// we can also use assignment operators for more concise code
      +attr = true;
       std::cout << "final attribute value: " << attr.value() << std::endl;
       

      @@ -649,19 +663,20 @@ 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");
      +
      // add node with some name
      +pugi::xml_node node = doc.append_child("node");
       
      -// add description node with text child
      -pugi::xml_node descr = node.append_child("description");
      +// add description node with text child
      +pugi::xml_node descr = node.append_child("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("param", descr);
      +// add param node before the description
      +pugi::xml_node param = node.insert_child_before("param", descr);
       
      -// add attributes to param node
      -param.append_attribute("name") = "version";
      +// 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";
       
      @@ -681,17 +696,18 @@ 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");
      +
      // 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");
      +// 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");
      +// we can also remove nodes/attributes by handles
      +pugi::xml_attribute id = param.attribute("name");
       param.remove_attribute(id);
       

      @@ -699,7 +715,7 @@

      Often after creating a new document or loading the existing one and processing @@ -724,9 +740,10 @@ of saving XML document to file (samples/save_file.cpp):

      +

      -
      // save document to file
      -std::cout << "Saving result: " << doc.save_file("save_file_output.xml") << std::endl;
      +
      // save document to file
      +std::cout << "Saving result: " << doc.save_file("save_file_output.xml") << std::endl;
       

      @@ -743,9 +760,10 @@ This is a simple example of saving XML document to standard output (samples/save_stream.cpp):

      +

      -
      // save document to standard output
      -std::cout << "Document:\n";
      +
      // save document to standard output
      +std::cout << "Document:\n";
       doc.save(std::cout);
       

      @@ -765,6 +783,7 @@ read the sample code for more complex examples:

      +

      struct xml_string_writer: pugi::xml_writer
       {
      @@ -789,7 +808,7 @@
       

      If you believe you've found a bug in pugixml, please file an issue via issue submission form. @@ -798,14 +817,14 @@ that uses pugixml and exhibits the bug, etc. Feature requests and contributions can be filed as issues, too.

      -

      - If filing an issue is not possible due to privacy or - other concerns, you can contact pugixml author by e-mail directly: arseny.kapoulkine@gmail.com. +

      + If filing an issue is not possible due to privacy or other concerns, you + can contact pugixml author by e-mail directly: arseny.kapoulkine@gmail.com.

      The pugixml library is distributed under the MIT license: @@ -854,7 +873,7 @@ pugixml

      - +

      Last revised: February 28, 2014 at 03:52:54 GMT

      Last revised: November 18, 2014 at 17:25:31 GMT

      -- cgit v1.2.3 From 417048d8cb8eb7cf3f4391aacd915b654f98c18e Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Wed, 19 Nov 2014 16:34:57 -0800 Subject: tests: Fix tests on various compilers Some compilers don't handle NaNs properly. Some compilers don't implement fmod in a IEEE-compatible way. Some compilers have exception handling codegen bugs (DMC...). --- tests/test_xpath.cpp | 2 ++ tests/test_xpath_operators.cpp | 4 ++++ tests/test_xpath_paths.cpp | 6 ++++++ 3 files changed, 12 insertions(+) diff --git a/tests/test_xpath.cpp b/tests/test_xpath.cpp index e410882..f5b4c66 100644 --- a/tests/test_xpath.cpp +++ b/tests/test_xpath.cpp @@ -639,9 +639,11 @@ TEST(xpath_allocate_string_out_of_memory) #else try { + #ifndef __DMC__ // DigitalMars exception handling crashes instead of catching the exception... xpath_query q(query.c_str()); CHECK_FORCE_FAIL("Expected out of memory exception"); + #endif } catch (const std::bad_alloc&) { diff --git a/tests/test_xpath_operators.cpp b/tests/test_xpath_operators.cpp index 57e3755..450af5d 100644 --- a/tests/test_xpath_operators.cpp +++ b/tests/test_xpath_operators.cpp @@ -492,6 +492,7 @@ TEST(xpath_operators_mod) CHECK_XPATH_NUMBER(c, STR("-5 mod 3"), -2); CHECK_XPATH_NUMBER(c, STR("-5 mod -3"), -2); +#if !defined(__BORLANDC__) // If either operand is NaN, the result is NaN CHECK_XPATH_NUMBER_NAN(c, STR("(0 div 0) mod 3")); CHECK_XPATH_NUMBER_NAN(c, STR("3 mod (0 div 0)")); @@ -505,14 +506,17 @@ TEST(xpath_operators_mod) CHECK_XPATH_NUMBER_NAN(c, STR("-1 mod 0")); CHECK_XPATH_NUMBER_NAN(c, STR("(1 div 0) mod 0")); CHECK_XPATH_NUMBER_NAN(c, STR("(-1 div 0) mod 0")); +#endif // If the dividend is finite and the divisor is an infinity, the result equals the dividend +#if !defined(_MSC_VER) && !defined(__MINGW32__) CHECK_XPATH_NUMBER(c, STR("1 mod (1 div 0)"), 1); CHECK_XPATH_NUMBER(c, STR("1 mod (-1 div 0)"), 1); CHECK_XPATH_NUMBER(c, STR("-1 mod (1 div 0)"), -1); CHECK_XPATH_NUMBER(c, STR("0 mod (1 div 0)"), 0); CHECK_XPATH_NUMBER(c, STR("0 mod (-1 div 0)"), 0); CHECK_XPATH_NUMBER(c, STR("100000 mod (1 div 0)"), 100000); +#endif // If the dividend is a zero and the divisor is finite, the result equals the dividend. CHECK_XPATH_NUMBER(c, STR("0 mod 1000000"), 0); diff --git a/tests/test_xpath_paths.cpp b/tests/test_xpath_paths.cpp index e51a395..69215d8 100644 --- a/tests/test_xpath_paths.cpp +++ b/tests/test_xpath_paths.cpp @@ -460,7 +460,10 @@ TEST_XML(xpath_paths_predicate_number_out_of_range, "< CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[-1 div 0]")); CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[1000000000000]")); CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[1 div 0]")); + +#ifndef MSVC6_NAN_BUG CHECK_XPATH_NODESET(n, STR("following-sibling::chapter[0 div 0]")); +#endif } TEST_XML(xpath_paths_predicate_constant_boolean, "") @@ -480,7 +483,10 @@ TEST_XML(xpath_paths_predicate_position_eq, " CHECK_XPATH_NODESET(doc, STR("node/chapter[position()=1]")) % 3; CHECK_XPATH_NODESET(doc, STR("node/chapter[position()=2+2]")) % 7; CHECK_XPATH_NODESET(doc, STR("node/chapter[position()=last()]")) % 8; + +#ifndef MSVC6_NAN_BUG CHECK_XPATH_NODESET(doc, STR("node/chapter[position()=string()]")) % 5; +#endif } TEST_XML(xpath_paths_predicate_several, "") -- cgit v1.2.3 From 5c5038c264ed7ecb02048257b956e5206c07a566 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Wed, 19 Nov 2014 19:50:40 -0800 Subject: Change has_declaration to work on node pointers This is more for consistency with the surrounding code than for performance. --- src/pugixml.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 3f6b2fd..f2f1dd9 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -3658,11 +3658,11 @@ PUGI__NS_BEGIN while (node != root); } - PUGI__FN bool has_declaration(xml_node node) + PUGI__FN bool has_declaration(xml_node_struct* node) { - for (xml_node child = node.first_child(); child; child = child.next_sibling()) + for (xml_node_struct* child = node->first_child; child; child = child->next_sibling) { - xml_node_type type = child.type(); + xml_node_type type = PUGI__NODETYPE(child); if (type == node_declaration) return true; if (type == node_element) return false; @@ -6066,7 +6066,7 @@ namespace pugi #endif } - if (!(flags & format_no_declaration) && !impl::has_declaration(*this)) + if (!(flags & format_no_declaration) && !impl::has_declaration(_root)) { buffered_writer.write_string(PUGIXML_TEXT(" Date: Wed, 19 Nov 2014 20:56:06 -0800 Subject: Add more assertions for page memory handling code --- src/pugixml.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index f2f1dd9..90befd8 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -1,5 +1,4 @@ /** -{ * pugixml parser - version 1.5 * -------------------------------------------------------- * Copyright (C) 2006-2014, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) @@ -326,7 +325,7 @@ PUGI__NS_BEGIN void* memory = xml_memory::allocate(size + xml_memory_page_alignment); if (!memory) return 0; - // align upwards to page boundary (note: this guarantees at least 1 usable byte before the page) + // align to next page boundary (note: this guarantees at least 1 usable byte before the page) char* page_memory = reinterpret_cast((reinterpret_cast(memory) + xml_memory_page_alignment) & ~(xml_memory_page_alignment - 1)); // prepare page structure @@ -336,6 +335,7 @@ PUGI__NS_BEGIN page->allocator = _root->allocator; // record the offset for freeing the memory block + assert(page_memory > memory && page_memory - static_cast(memory) <= 127); page_memory[-1] = static_cast(page_memory - static_cast(memory)); return page; @@ -5966,6 +5966,7 @@ namespace pugi // destroy dynamic storage, leave sentinel page (it's in static memory) impl::xml_memory_page* root_page = reinterpret_cast(_root->header & impl::xml_memory_page_pointer_mask); assert(root_page && !root_page->prev); + assert(reinterpret_cast(root_page) >= _memory && reinterpret_cast(root_page) < _memory + sizeof(_memory)); for (impl::xml_memory_page* page = root_page->next; page; ) { -- cgit v1.2.3 From c579d99649bae59aaf5344e3d428201113fab1e9 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Wed, 19 Nov 2014 20:56:36 -0800 Subject: Prevent depth underflow when printing documents Since depth is unsigned this is actually well-defined but it's better to not have the underflow anyway. --- src/pugixml.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 90befd8..961e5f3 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -3643,11 +3643,12 @@ PUGI__NS_BEGIN } node = node->parent; - depth--; // write closing node if (PUGI__NODETYPE(node) == node_element) { + depth--; + if (indent_length) text_output_indent(writer, indent, indent_length, depth); -- cgit v1.2.3 From 6d048deba8dfb8ccb8122b6c905b08b75f5090bf Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Wed, 19 Nov 2014 20:57:22 -0800 Subject: Make sure remove_node fully detaches the node Right now remove_node is only used in contexts where parent is reset after removing but this might be important in the future. --- src/pugixml.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 961e5f3..194c77d 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -711,6 +711,7 @@ PUGI__NS_BEGIN else parent->first_child = node->next_sibling; + node->parent = 0; node->prev_sibling_c = 0; node->next_sibling = 0; } -- cgit v1.2.3 From b8437664a9d6b5697f09611b96951c005ab2554a Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Wed, 19 Nov 2014 22:44:08 -0800 Subject: XPath: Minor string operation refactoring Extract end of string to rend and add comments to translate_table. --- src/pugixml.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 194c77d..c15ed6b 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -7435,6 +7435,7 @@ PUGI__NS_BEGIN if (fc >= 128 || tc >= 128) return 0; + // code=128 means "skip character" if (!table[fc]) table[fc] = static_cast(tc ? tc : 128); @@ -7469,6 +7470,8 @@ PUGI__NS_BEGIN { unsigned char code = table[index]; + // code=128 means "skip character" (table size is 128 so 128 can be a special value) + // this code skips these characters without extra branches *write = static_cast(code); write += 1 - (code >> 7); } @@ -9525,9 +9528,10 @@ PUGI__NS_BEGIN const char_t* pos = find_substring(s.c_str(), p.c_str()); if (!pos) return xpath_string(); - const char_t* result = pos + p.length(); + const char_t* rbegin = pos + p.length(); + const char_t* rend = s.c_str() + s.length(); - return s.uses_heap() ? xpath_string::from_heap(result, s.c_str() + s.length(), stack.result) : xpath_string::from_const(result); + return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin); } case ast_func_substring_2: @@ -9548,8 +9552,9 @@ PUGI__NS_BEGIN assert(1 <= pos && pos <= s_length + 1); const char_t* rbegin = s.c_str() + (pos - 1); + const char_t* rend = s.c_str() + s.length(); - return s.uses_heap() ? xpath_string::from_heap(rbegin, s.c_str() + s.length(), stack.result) : xpath_string::from_const(rbegin); + return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin); } case ast_func_substring_3: -- cgit v1.2.3 From cd62478108860e36b5cab30d85640492d0f32d91 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Wed, 19 Nov 2014 22:50:06 -0800 Subject: XPath: Refactor eval_once to use set type This will allow us to implement nodeset_eval_last evaluation mode if necessary without relying on a fragile boolean argument. --- src/pugixml.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index c15ed6b..b69ba2c 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -8436,9 +8436,9 @@ PUGI__NS_BEGIN return false; } - static bool eval_once(bool forward, nodeset_eval_t eval) + static bool eval_once(xpath_node_set::type_t type, nodeset_eval_t eval) { - return forward ? eval != nodeset_eval_all : eval == nodeset_eval_any; + return type == xpath_node_set::type_sorted ? eval != nodeset_eval_all : eval == nodeset_eval_any; } template static bool compare_rel(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp) @@ -8610,7 +8610,7 @@ PUGI__NS_BEGIN { if (ns.size() == first) return; - bool last_once = eval_once(ns.type() == xpath_node_set::type_sorted, eval); + bool last_once = eval_once(ns.type(), eval); for (xpath_ast_node* pred = _right; pred; pred = pred->_next) pred->apply_predicate(ns, first, stack, !pred->_next && last_once); @@ -9008,7 +9008,7 @@ PUGI__NS_BEGIN template void step_fill(xpath_node_set_raw& ns, const xpath_node& xn, xpath_allocator* alloc, bool once, T v) { const axis_t axis = T::axis; - bool axis_has_attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self); + const bool axis_has_attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self); if (xn.node()) step_fill(ns, xn.node().internal_object(), alloc, once, v); @@ -9019,15 +9019,16 @@ PUGI__NS_BEGIN template xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, nodeset_eval_t eval, T v) { const axis_t axis = T::axis; - bool axis_reverse = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling); + const bool axis_reverse = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling); + const xpath_node_set::type_t axis_type = axis_reverse ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted; bool once = (axis == axis_attribute && _test == nodetest_name) || - (!_right && eval_once(!axis_reverse, eval)) || + (!_right && eval_once(axis_type, eval)) || (_right && !_right->_next && _right->_test == predicate_constant_one); xpath_node_set_raw ns; - ns.set_type(axis_reverse ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted); + ns.set_type(axis_type); if (_left) { @@ -9693,7 +9694,7 @@ PUGI__NS_BEGIN // either expression is a number or it contains position() call; sort by document order if (_test != predicate_posinv) set.sort_do(); - bool once = eval_once(set.type() == xpath_node_set::type_sorted, eval); + bool once = eval_once(set.type(), eval); apply_predicate(set, 0, stack, once); -- cgit v1.2.3 From 8f85b1ba7afb77228cffb31452272854abfa931e Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Thu, 20 Nov 2014 08:54:03 -0800 Subject: Minor refactoring of tree modification Remove redundant this-> from type() call (argument used to be called type, but it's now type_). Use _root member directly when possible instead of calling internal_object. --- src/pugixml.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index b69ba2c..75b5295 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -4970,7 +4970,7 @@ namespace pugi PUGI__FN xml_node xml_node::append_child(xml_node_type type_) { - if (!impl::allow_insert_child(this->type(), type_)) return xml_node(); + if (!impl::allow_insert_child(type(), type_)) return xml_node(); xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); if (!n) return xml_node(); @@ -4984,7 +4984,7 @@ namespace pugi PUGI__FN xml_node xml_node::prepend_child(xml_node_type type_) { - if (!impl::allow_insert_child(this->type(), type_)) return xml_node(); + if (!impl::allow_insert_child(type(), type_)) return xml_node(); xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); if (!n) return xml_node(); @@ -4998,7 +4998,7 @@ namespace pugi PUGI__FN xml_node xml_node::insert_child_before(xml_node_type type_, const xml_node& node) { - if (!impl::allow_insert_child(this->type(), type_)) return xml_node(); + if (!impl::allow_insert_child(type(), type_)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); @@ -5013,7 +5013,7 @@ namespace pugi PUGI__FN xml_node xml_node::insert_child_after(xml_node_type type_, const xml_node& node) { - if (!impl::allow_insert_child(this->type(), type_)) return xml_node(); + if (!impl::allow_insert_child(type(), type_)) return xml_node(); if (!node._root || node._root->parent != _root) return xml_node(); xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); @@ -5066,7 +5066,7 @@ namespace pugi { xml_node result = append_child(proto.type()); - if (result) impl::node_copy_tree(result.internal_object(), proto.internal_object()); + if (result) impl::node_copy_tree(result._root, proto._root); return result; } @@ -5075,7 +5075,7 @@ namespace pugi { xml_node result = prepend_child(proto.type()); - if (result) impl::node_copy_tree(result.internal_object(), proto.internal_object()); + if (result) impl::node_copy_tree(result._root, proto._root); return result; } @@ -5084,7 +5084,7 @@ namespace pugi { xml_node result = insert_child_after(proto.type(), node); - if (result) impl::node_copy_tree(result.internal_object(), proto.internal_object()); + if (result) impl::node_copy_tree(result._root, proto._root); return result; } @@ -5093,7 +5093,7 @@ namespace pugi { xml_node result = insert_child_before(proto.type(), node); - if (result) impl::node_copy_tree(result.internal_object(), proto.internal_object()); + if (result) impl::node_copy_tree(result._root, proto._root); return result; } -- cgit v1.2.3 From a0dc468170a9f429446feafea48fc73ae348b648 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Thu, 20 Nov 2014 20:29:21 -0800 Subject: Refactor node type checks for attribute insertion Add allow_insert_attribute (similar to allow_insert_child). --- src/pugixml.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 75b5295..420ac1f 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -3682,6 +3682,11 @@ PUGI__NS_BEGIN return false; } + PUGI__FN bool allow_insert_attribute(xml_node_type parent) + { + return parent == node_element || parent == node_declaration; + } + PUGI__FN bool allow_insert_child(xml_node_type parent, xml_node_type child) { if (parent != node_document && parent != node_element) return false; @@ -4872,7 +4877,7 @@ namespace pugi PUGI__FN xml_attribute xml_node::append_attribute(const char_t* name_) { - if (type() != node_element && type() != node_declaration) return xml_attribute(); + if (!impl::allow_insert_attribute(type())) return xml_attribute(); xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root))); if (!a) return xml_attribute(); @@ -4886,7 +4891,7 @@ namespace pugi PUGI__FN xml_attribute xml_node::prepend_attribute(const char_t* name_) { - if (type() != node_element && type() != node_declaration) return xml_attribute(); + if (!impl::allow_insert_attribute(type())) return xml_attribute(); xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root))); if (!a) return xml_attribute(); @@ -4900,7 +4905,7 @@ namespace pugi PUGI__FN xml_attribute xml_node::insert_attribute_after(const char_t* name_, const xml_attribute& attr) { - if (type() != node_element && type() != node_declaration) return xml_attribute(); + if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root))); @@ -4915,7 +4920,7 @@ namespace pugi PUGI__FN xml_attribute xml_node::insert_attribute_before(const char_t* name_, const xml_attribute& attr) { - if (type() != node_element && type() != node_declaration) return xml_attribute(); + if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root))); -- cgit v1.2.3 From 125aa55061ccde4ae7351a9a6c7270a15c9e0204 Mon Sep 17 00:00:00 2001 From: Arseny Kapoulkine Date: Thu, 20 Nov 2014 23:39:40 -0800 Subject: Fix node_declaration copying with empty name node_copy_string relied on the fact that target node had an empty name and value. Normally this is a safe assumption (and a good one to make since it makes copying faster), however it was not checked and there was one case when it did not hold. Since we're reusing the logic for inserting nodes, newly inserted declaration nodes had the name set automatically to xml, which in our case violates the assumption and is counter-productive since we'll override the name right after setting it. For now the best solution is to do the same insertion manually - that results in some code duplication that we can refactor later (same logic is partially shared by _move variants anyway so on a level duplicating is not that bad). --- src/pugixml.cpp | 48 +++++++++++++++++++++++++++++++++++------------ tests/test_dom_modify.cpp | 12 ++++++++++++ 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 420ac1f..ff84d44 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -3722,6 +3722,8 @@ PUGI__NS_BEGIN PUGI__FN void node_copy_string(char_t*& dest, uintptr_t& header, uintptr_t header_mask, char_t* source, uintptr_t& source_header, xml_allocator* alloc) { + assert(!dest && (header & header_mask) == 0); + if (source) { if (alloc && (source_header & header_mask) == 0) @@ -5069,38 +5071,60 @@ namespace pugi PUGI__FN xml_node xml_node::append_copy(const xml_node& proto) { - xml_node result = append_child(proto.type()); + xml_node_type type_ = proto.type(); + if (!impl::allow_insert_child(type(), type_)) return xml_node(); + + xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); + if (!n) return xml_node(); - if (result) impl::node_copy_tree(result._root, proto._root); + impl::append_node(n._root, _root); + impl::node_copy_tree(n._root, proto._root); - return result; + return n; } PUGI__FN xml_node xml_node::prepend_copy(const xml_node& proto) { - xml_node result = prepend_child(proto.type()); + xml_node_type type_ = proto.type(); + if (!impl::allow_insert_child(type(), type_)) return xml_node(); - if (result) impl::node_copy_tree(result._root, proto._root); + xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); + if (!n) return xml_node(); - return result; + impl::prepend_node(n._root, _root); + impl::node_copy_tree(n._root, proto._root); + + return n; } PUGI__FN xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node) { - xml_node result = insert_child_after(proto.type(), node); + xml_node_type type_ = proto.type(); + if (!impl::allow_insert_child(type(), type_)) return xml_node(); + if (!node._root || node._root->parent != _root) return xml_node(); - if (result) impl::node_copy_tree(result._root, proto._root); + xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); + if (!n) return xml_node(); - return result; + impl::insert_node_after(n._root, node._root); + impl::node_copy_tree(n._root, proto._root); + + return n; } PUGI__FN xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node) { - xml_node result = insert_child_before(proto.type(), node); + xml_node_type type_ = proto.type(); + if (!impl::allow_insert_child(type(), type_)) return xml_node(); + if (!node._root || node._root->parent != _root) return xml_node(); - if (result) impl::node_copy_tree(result._root, proto._root); + xml_node n(impl::allocate_node(impl::get_allocator(_root), type_)); + if (!n) return xml_node(); - return result; + impl::insert_node_before(n._root, node._root); + impl::node_copy_tree(n._root, proto._root); + + return n; } PUGI__FN xml_node xml_node::append_move(const xml_node& moved) diff --git a/tests/test_dom_modify.cpp b/tests/test_dom_modify.cpp index 8665af9..7863718 100644 --- a/tests/test_dom_modify.cpp +++ b/tests/test_dom_modify.cpp @@ -1426,3 +1426,15 @@ TEST_XML(dom_node_set_deallocate, "text") CHECK_NODE(doc, STR("<:anonymous :anonymous=\"\">")); } + +TEST(dom_node_copy_declaration_empty_name) +{ + xml_document doc1; + xml_node decl1 = doc1.append_child(node_declaration); + decl1.set_name(STR("")); + + xml_document doc2; + xml_node decl2 = doc2.append_copy(decl1); + + CHECK_STRING(decl2.name(), STR("")); +} -- cgit v1.2.3