From 1ef1022fedf28d215ac26943c46d0d3d697c2b81 Mon Sep 17 00:00:00 2001 From: Marc-Etienne Barrut Date: Sat, 11 Apr 2015 10:53:25 +0900 Subject: [PATCH 001/101] Initial commit --- LICENSE | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6410342 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Marc-Etienne Barrut + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + From 05635ceadcda8fafb9eedfdc09e9ed0cb25407f0 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Sat, 11 Apr 2015 10:57:49 +0900 Subject: [PATCH 002/101] first import --- .gitignore | 57 + rapidxml-1.13/license.txt | 52 + rapidxml-1.13/rapidxml.hpp | 2596 ++++++++++++++++++++++++++ rapidxml-1.13/rapidxml_iterators.hpp | 174 ++ rapidxml-1.13/rapidxml_print.hpp | 421 +++++ rapidxml-1.13/rapidxml_utils.hpp | 122 ++ rapidxml.cpp | 81 + setup.py | 29 + 8 files changed, 3532 insertions(+) create mode 100644 .gitignore create mode 100644 rapidxml-1.13/license.txt create mode 100644 rapidxml-1.13/rapidxml.hpp create mode 100644 rapidxml-1.13/rapidxml_iterators.hpp create mode 100644 rapidxml-1.13/rapidxml_print.hpp create mode 100644 rapidxml-1.13/rapidxml_utils.hpp create mode 100644 rapidxml.cpp create mode 100644 setup.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..048d80c --- /dev/null +++ b/.gitignore @@ -0,0 +1,57 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.cache +nosetests.xml +coverage.xml + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# local files +files/ diff --git a/rapidxml-1.13/license.txt b/rapidxml-1.13/license.txt new file mode 100644 index 0000000..0095bc7 --- /dev/null +++ b/rapidxml-1.13/license.txt @@ -0,0 +1,52 @@ +Use of this software is granted under one of the following two licenses, +to be chosen freely by the user. + +1. Boost Software License - Version 1.0 - August 17th, 2003 +=============================================================================== + +Copyright (c) 2006, 2007 Marcin Kalicinski + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +2. The MIT License +=============================================================================== + +Copyright (c) 2006, 2007 Marcin Kalicinski + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. diff --git a/rapidxml-1.13/rapidxml.hpp b/rapidxml-1.13/rapidxml.hpp new file mode 100644 index 0000000..6b82f20 --- /dev/null +++ b/rapidxml-1.13/rapidxml.hpp @@ -0,0 +1,2596 @@ +#ifndef RAPIDXML_HPP_INCLUDED +#define RAPIDXML_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml.hpp This file contains rapidxml parser and DOM implementation + +// If standard library is disabled, user must provide implementations of required functions and typedefs +#if !defined(RAPIDXML_NO_STDLIB) + #include // For std::size_t + #include // For assert + #include // For placement new +#endif + +// On MSVC, disable "conditional expression is constant" warning (level 4). +// This warning is almost impossible to avoid with certain types of templated code +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable:4127) // Conditional expression is constant +#endif + +/////////////////////////////////////////////////////////////////////////// +// RAPIDXML_PARSE_ERROR + +#if defined(RAPIDXML_NO_EXCEPTIONS) + +#define RAPIDXML_PARSE_ERROR(what, where) { parse_error_handler(what, where); assert(0); } + +namespace rapidxml +{ + //! When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, + //! this function is called to notify user about the error. + //! It must be defined by the user. + //!

+ //! This function cannot return. If it does, the results are undefined. + //!

+ //! A very simple definition might look like that: + //!
+    //! void %rapidxml::%parse_error_handler(const char *what, void *where)
+    //! {
+    //!     std::cout << "Parse error: " << what << "\n";
+    //!     std::abort();
+    //! }
+    //! 
+ //! \param what Human readable description of the error. + //! \param where Pointer to character data where error was detected. + void parse_error_handler(const char *what, void *where); +} + +#else + +#include // For std::exception + +#define RAPIDXML_PARSE_ERROR(what, where) throw parse_error(what, where) + +namespace rapidxml +{ + + //! Parse error exception. + //! This exception is thrown by the parser when an error occurs. + //! Use what() function to get human-readable error message. + //! Use where() function to get a pointer to position within source text where error was detected. + //!

+ //! If throwing exceptions by the parser is undesirable, + //! it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included. + //! This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception. + //! This function must be defined by the user. + //!

+ //! This class derives from std::exception class. + class parse_error: public std::exception + { + + public: + + //! Constructs parse error + parse_error(const char *what, void *where) + : m_what(what) + , m_where(where) + { + } + + //! Gets human readable description of error. + //! \return Pointer to null terminated description of the error. + virtual const char *what() const throw() + { + return m_what; + } + + //! Gets pointer to character data where error happened. + //! Ch should be the same as char type of xml_document that produced the error. + //! \return Pointer to location within the parsed string where error occured. + template + Ch *where() const + { + return reinterpret_cast(m_where); + } + + private: + + const char *m_what; + void *m_where; + + }; +} + +#endif + +/////////////////////////////////////////////////////////////////////////// +// Pool sizes + +#ifndef RAPIDXML_STATIC_POOL_SIZE + // Size of static memory block of memory_pool. + // Define RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. + // No dynamic memory allocations are performed by memory_pool until static memory is exhausted. + #define RAPIDXML_STATIC_POOL_SIZE (64 * 1024) +#endif + +#ifndef RAPIDXML_DYNAMIC_POOL_SIZE + // Size of dynamic memory block of memory_pool. + // Define RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value. + // After the static block is exhausted, dynamic blocks with approximately this size are allocated by memory_pool. + #define RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024) +#endif + +#ifndef RAPIDXML_ALIGNMENT + // Memory allocation alignment. + // Define RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to override the default value, which is the size of pointer. + // All memory allocations for nodes, attributes and strings will be aligned to this value. + // This must be a power of 2 and at least 1, otherwise memory_pool will not work. + #define RAPIDXML_ALIGNMENT sizeof(void *) +#endif + +namespace rapidxml +{ + // Forward declarations + template class xml_node; + template class xml_attribute; + template class xml_document; + + //! Enumeration listing all node types produced by the parser. + //! Use xml_node::type() function to query node type. + enum node_type + { + node_document, //!< A document node. Name and value are empty. + node_element, //!< An element node. Name contains element name. Value contains text of first data node. + node_data, //!< A data node. Name is empty. Value contains data text. + node_cdata, //!< A CDATA node. Name is empty. Value contains data text. + node_comment, //!< A comment node. Name is empty. Value contains comment text. + node_declaration, //!< A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes. + node_doctype, //!< A DOCTYPE node. Name is empty. Value contains DOCTYPE text. + node_pi //!< A PI node. Name contains target. Value contains instructions. + }; + + /////////////////////////////////////////////////////////////////////// + // Parsing flags + + //! Parse flag instructing the parser to not create data nodes. + //! Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_data_nodes = 0x1; + + //! Parse flag instructing the parser to not use text of first data node as a value of parent element. + //! Can be combined with other flags by use of | operator. + //! Note that child data nodes of element node take precendence over its value when printing. + //! That is, if element has one or more child data nodes and a value, the value will be ignored. + //! Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements. + //!

+ //! See xml_document::parse() function. + const int parse_no_element_values = 0x2; + + //! Parse flag instructing the parser to not place zero terminators after strings in the source text. + //! By default zero terminators are placed, modifying source text. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_string_terminators = 0x4; + + //! Parse flag instructing the parser to not translate entities in the source text. + //! By default entities are translated, modifying source text. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_entity_translation = 0x8; + + //! Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters. + //! By default, UTF-8 handling is enabled. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_no_utf8 = 0x10; + + //! Parse flag instructing the parser to create XML declaration node. + //! By default, declaration node is not created. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_declaration_node = 0x20; + + //! Parse flag instructing the parser to create comments nodes. + //! By default, comment nodes are not created. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_comment_nodes = 0x40; + + //! Parse flag instructing the parser to create DOCTYPE node. + //! By default, doctype node is not created. + //! Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_doctype_node = 0x80; + + //! Parse flag instructing the parser to create PI nodes. + //! By default, PI nodes are not created. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_pi_nodes = 0x100; + + //! Parse flag instructing the parser to validate closing tag names. + //! If not set, name inside closing tag is irrelevant to the parser. + //! By default, closing tags are not validated. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_validate_closing_tags = 0x200; + + //! Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes. + //! By default, whitespace is not trimmed. + //! This flag does not cause the parser to modify source text. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_trim_whitespace = 0x400; + + //! Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character. + //! Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag. + //! By default, whitespace is not normalized. + //! If this flag is specified, source text will be modified. + //! Can be combined with other flags by use of | operator. + //!

+ //! See xml_document::parse() function. + const int parse_normalize_whitespace = 0x800; + + // Compound flags + + //! Parse flags which represent default behaviour of the parser. + //! This is always equal to 0, so that all other flags can be simply ored together. + //! Normally there is no need to inconveniently disable flags by anding with their negated (~) values. + //! This also means that meaning of each flag is a negation of the default setting. + //! For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is enabled by default, + //! and using the flag will disable it. + //!

+ //! See xml_document::parse() function. + const int parse_default = 0; + + //! A combination of parse flags that forbids any modifications of the source text. + //! This also results in faster parsing. However, note that the following will occur: + //!
    + //!
  • names and values of nodes will not be zero terminated, you have to use xml_base::name_size() and xml_base::value_size() functions to determine where name and value ends
  • + //!
  • entities will not be translated
  • + //!
  • whitespace will not be normalized
  • + //!
+ //! See xml_document::parse() function. + const int parse_non_destructive = parse_no_string_terminators | parse_no_entity_translation; + + //! A combination of parse flags resulting in fastest possible parsing, without sacrificing important data. + //!

+ //! See xml_document::parse() function. + const int parse_fastest = parse_non_destructive | parse_no_data_nodes; + + //! A combination of parse flags resulting in largest amount of data being extracted. + //! This usually results in slowest parsing. + //!

+ //! See xml_document::parse() function. + const int parse_full = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags; + + /////////////////////////////////////////////////////////////////////// + // Internals + + //! \cond internal + namespace internal + { + + // Struct that contains lookup tables for the parser + // It must be a template to allow correct linking (because it has static data members, which are defined in a header file). + template + struct lookup_tables + { + static const unsigned char lookup_whitespace[256]; // Whitespace table + static const unsigned char lookup_node_name[256]; // Node name table + static const unsigned char lookup_text[256]; // Text table + static const unsigned char lookup_text_pure_no_ws[256]; // Text table + static const unsigned char lookup_text_pure_with_ws[256]; // Text table + static const unsigned char lookup_attribute_name[256]; // Attribute name table + static const unsigned char lookup_attribute_data_1[256]; // Attribute data table with single quote + static const unsigned char lookup_attribute_data_1_pure[256]; // Attribute data table with single quote + static const unsigned char lookup_attribute_data_2[256]; // Attribute data table with double quotes + static const unsigned char lookup_attribute_data_2_pure[256]; // Attribute data table with double quotes + static const unsigned char lookup_digits[256]; // Digits + static const unsigned char lookup_upcase[256]; // To uppercase conversion table for ASCII characters + }; + + // Find length of the string + template + inline std::size_t measure(const Ch *p) + { + const Ch *tmp = p; + while (*tmp) + ++tmp; + return tmp - p; + } + + // Compare strings for equality + template + inline bool compare(const Ch *p1, std::size_t size1, const Ch *p2, std::size_t size2, bool case_sensitive) + { + if (size1 != size2) + return false; + if (case_sensitive) + { + for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) + if (*p1 != *p2) + return false; + } + else + { + for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2) + if (lookup_tables<0>::lookup_upcase[static_cast(*p1)] != lookup_tables<0>::lookup_upcase[static_cast(*p2)]) + return false; + } + return true; + } + } + //! \endcond + + /////////////////////////////////////////////////////////////////////// + // Memory pool + + //! This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation. + //! In most cases, you will not need to use this class directly. + //! However, if you need to create nodes manually or modify names/values of nodes, + //! you are encouraged to use memory_pool of relevant xml_document to allocate the memory. + //! Not only is this faster than allocating them by using new operator, + //! but also their lifetime will be tied to the lifetime of document, + //! possibly simplyfing memory management. + //!

+ //! Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool. + //! You can also call allocate_string() function to allocate strings. + //! Such strings can then be used as names or values of nodes without worrying about their lifetime. + //! Note that there is no free() function -- all allocations are freed at once when clear() function is called, + //! or when the pool is destroyed. + //!

+ //! It is also possible to create a standalone memory_pool, and use it + //! to allocate nodes, whose lifetime will not be tied to any document. + //!

+ //! Pool maintains RAPIDXML_STATIC_POOL_SIZE bytes of statically allocated memory. + //! Until static memory is exhausted, no dynamic memory allocations are done. + //! When static memory is exhausted, pool allocates additional blocks of memory of size RAPIDXML_DYNAMIC_POOL_SIZE each, + //! by using global new[] and delete[] operators. + //! This behaviour can be changed by setting custom allocation routines. + //! Use set_allocator() function to set them. + //!

+ //! Allocations for nodes, attributes and strings are aligned at RAPIDXML_ALIGNMENT bytes. + //! This value defaults to the size of pointer on target architecture. + //!

+ //! To obtain absolutely top performance from the parser, + //! it is important that all nodes are allocated from a single, contiguous block of memory. + //! Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably. + //! If required, you can tweak RAPIDXML_STATIC_POOL_SIZE, RAPIDXML_DYNAMIC_POOL_SIZE and RAPIDXML_ALIGNMENT + //! to obtain best wasted memory to performance compromise. + //! To do it, define their values before rapidxml.hpp file is included. + //! \param Ch Character type of created nodes. + template + class memory_pool + { + + public: + + //! \cond internal + typedef void *(alloc_func)(std::size_t); // Type of user-defined function used to allocate memory + typedef void (free_func)(void *); // Type of user-defined function used to free memory + //! \endcond + + //! Constructs empty pool with default allocator functions. + memory_pool() + : m_alloc_func(0) + , m_free_func(0) + { + init(); + } + + //! Destroys pool and frees all the memory. + //! This causes memory occupied by nodes allocated by the pool to be freed. + //! Nodes allocated from the pool are no longer valid. + ~memory_pool() + { + clear(); + } + + //! Allocates a new node from the pool, and optionally assigns name and value to it. + //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param type Type of node to create. + //! \param name Name to assign to the node, or 0 to assign no name. + //! \param value Value to assign to the node, or 0 to assign no value. + //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. + //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. + //! \return Pointer to allocated node. This pointer will never be NULL. + xml_node *allocate_node(node_type type, + const Ch *name = 0, const Ch *value = 0, + std::size_t name_size = 0, std::size_t value_size = 0) + { + void *memory = allocate_aligned(sizeof(xml_node)); + xml_node *node = new(memory) xml_node(type); + if (name) + { + if (name_size > 0) + node->name(name, name_size); + else + node->name(name); + } + if (value) + { + if (value_size > 0) + node->value(value, value_size); + else + node->value(value); + } + return node; + } + + //! Allocates a new attribute from the pool, and optionally assigns name and value to it. + //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param name Name to assign to the attribute, or 0 to assign no name. + //! \param value Value to assign to the attribute, or 0 to assign no value. + //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string. + //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string. + //! \return Pointer to allocated attribute. This pointer will never be NULL. + xml_attribute *allocate_attribute(const Ch *name = 0, const Ch *value = 0, + std::size_t name_size = 0, std::size_t value_size = 0) + { + void *memory = allocate_aligned(sizeof(xml_attribute)); + xml_attribute *attribute = new(memory) xml_attribute; + if (name) + { + if (name_size > 0) + attribute->name(name, name_size); + else + attribute->name(name); + } + if (value) + { + if (value_size > 0) + attribute->value(value, value_size); + else + attribute->value(value); + } + return attribute; + } + + //! Allocates a char array of given size from the pool, and optionally copies a given string to it. + //! If the allocation request cannot be accomodated, this function will throw std::bad_alloc. + //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function + //! will call rapidxml::parse_error_handler() function. + //! \param source String to initialize the allocated memory with, or 0 to not initialize it. + //! \param size Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated. + //! \return Pointer to allocated char array. This pointer will never be NULL. + Ch *allocate_string(const Ch *source = 0, std::size_t size = 0) + { + assert(source || size); // Either source or size (or both) must be specified + if (size == 0) + size = internal::measure(source) + 1; + Ch *result = static_cast(allocate_aligned(size * sizeof(Ch))); + if (source) + for (std::size_t i = 0; i < size; ++i) + result[i] = source[i]; + return result; + } + + //! Clones an xml_node and its hierarchy of child nodes and attributes. + //! Nodes and attributes are allocated from this memory pool. + //! Names and values are not cloned, they are shared between the clone and the source. + //! Result node can be optionally specified as a second parameter, + //! in which case its contents will be replaced with cloned source node. + //! This is useful when you want to clone entire document. + //! \param source Node to clone. + //! \param result Node to put results in, or 0 to automatically allocate result node + //! \return Pointer to cloned node. This pointer will never be NULL. + xml_node *clone_node(const xml_node *source, xml_node *result = 0) + { + // Prepare result node + if (result) + { + result->remove_all_attributes(); + result->remove_all_nodes(); + result->type(source->type()); + } + else + result = allocate_node(source->type()); + + // Clone name and value + result->name(source->name(), source->name_size()); + result->value(source->value(), source->value_size()); + + // Clone child nodes and attributes + for (xml_node *child = source->first_node(); child; child = child->next_sibling()) + result->append_node(clone_node(child)); + for (xml_attribute *attr = source->first_attribute(); attr; attr = attr->next_attribute()) + result->append_attribute(allocate_attribute(attr->name(), attr->value(), attr->name_size(), attr->value_size())); + + return result; + } + + //! Clears the pool. + //! This causes memory occupied by nodes allocated by the pool to be freed. + //! Any nodes or strings allocated from the pool will no longer be valid. + void clear() + { + while (m_begin != m_static_memory) + { + char *previous_begin = reinterpret_cast
(align(m_begin))->previous_begin; + if (m_free_func) + m_free_func(m_begin); + else + delete[] m_begin; + m_begin = previous_begin; + } + init(); + } + + //! Sets or resets the user-defined memory allocation functions for the pool. + //! This can only be called when no memory is allocated from the pool yet, otherwise results are undefined. + //! Allocation function must not return invalid pointer on failure. It should either throw, + //! stop the program, or use longjmp() function to pass control to other place of program. + //! If it returns invalid pointer, results are undefined. + //!

+ //! User defined allocation functions must have the following forms: + //!
+ //!
void *allocate(std::size_t size); + //!
void free(void *pointer); + //!

+ //! \param af Allocation function, or 0 to restore default function + //! \param ff Free function, or 0 to restore default function + void set_allocator(alloc_func *af, free_func *ff) + { + assert(m_begin == m_static_memory && m_ptr == align(m_begin)); // Verify that no memory is allocated yet + m_alloc_func = af; + m_free_func = ff; + } + + private: + + struct header + { + char *previous_begin; + }; + + void init() + { + m_begin = m_static_memory; + m_ptr = align(m_begin); + m_end = m_static_memory + sizeof(m_static_memory); + } + + char *align(char *ptr) + { + std::size_t alignment = ((RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (RAPIDXML_ALIGNMENT - 1))) & (RAPIDXML_ALIGNMENT - 1)); + return ptr + alignment; + } + + char *allocate_raw(std::size_t size) + { + // Allocate + void *memory; + if (m_alloc_func) // Allocate memory using either user-specified allocation function or global operator new[] + { + memory = m_alloc_func(size); + assert(memory); // Allocator is not allowed to return 0, on failure it must either throw, stop the program or use longjmp + } + else + { + memory = new char[size]; +#ifdef RAPIDXML_NO_EXCEPTIONS + if (!memory) // If exceptions are disabled, verify memory allocation, because new will not be able to throw bad_alloc + RAPIDXML_PARSE_ERROR("out of memory", 0); +#endif + } + return static_cast(memory); + } + + void *allocate_aligned(std::size_t size) + { + // Calculate aligned pointer + char *result = align(m_ptr); + + // If not enough memory left in current pool, allocate a new pool + if (result + size > m_end) + { + // Calculate required pool size (may be bigger than RAPIDXML_DYNAMIC_POOL_SIZE) + std::size_t pool_size = RAPIDXML_DYNAMIC_POOL_SIZE; + if (pool_size < size) + pool_size = size; + + // Allocate + std::size_t alloc_size = sizeof(header) + (2 * RAPIDXML_ALIGNMENT - 2) + pool_size; // 2 alignments required in worst case: one for header, one for actual allocation + char *raw_memory = allocate_raw(alloc_size); + + // Setup new pool in allocated memory + char *pool = align(raw_memory); + header *new_header = reinterpret_cast
(pool); + new_header->previous_begin = m_begin; + m_begin = raw_memory; + m_ptr = pool + sizeof(header); + m_end = raw_memory + alloc_size; + + // Calculate aligned pointer again using new pool + result = align(m_ptr); + } + + // Update pool and return aligned pointer + m_ptr = result + size; + return result; + } + + char *m_begin; // Start of raw memory making up current pool + char *m_ptr; // First free byte in current pool + char *m_end; // One past last available byte in current pool + char m_static_memory[RAPIDXML_STATIC_POOL_SIZE]; // Static raw memory + alloc_func *m_alloc_func; // Allocator function, or 0 if default is to be used + free_func *m_free_func; // Free function, or 0 if default is to be used + }; + + /////////////////////////////////////////////////////////////////////////// + // XML base + + //! Base class for xml_node and xml_attribute implementing common functions: + //! name(), name_size(), value(), value_size() and parent(). + //! \param Ch Character type to use + template + class xml_base + { + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + // Construct a base with empty name, value and parent + xml_base() + : m_name(0) + , m_value(0) + , m_parent(0) + { + } + + /////////////////////////////////////////////////////////////////////////// + // Node data access + + //! Gets name of the node. + //! Interpretation of name depends on type of node. + //! Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. + //!

+ //! Use name_size() function to determine length of the name. + //! \return Name of node, or empty string if node has no name. + Ch *name() const + { + return m_name ? m_name : nullstr(); + } + + //! Gets size of node name, not including terminator character. + //! This function works correctly irrespective of whether name is or is not zero terminated. + //! \return Size of node name, in characters. + std::size_t name_size() const + { + return m_name ? m_name_size : 0; + } + + //! Gets value of node. + //! Interpretation of value depends on type of node. + //! Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse. + //!

+ //! Use value_size() function to determine length of the value. + //! \return Value of node, or empty string if node has no value. + Ch *value() const + { + return m_value ? m_value : nullstr(); + } + + //! Gets size of node value, not including terminator character. + //! This function works correctly irrespective of whether value is or is not zero terminated. + //! \return Size of node value, in characters. + std::size_t value_size() const + { + return m_value ? m_value_size : 0; + } + + /////////////////////////////////////////////////////////////////////////// + // Node modification + + //! Sets name of node to a non zero-terminated string. + //! See \ref ownership_of_strings. + //!

+ //! Note that node does not own its name or value, it only stores a pointer to it. + //! It will not delete or otherwise free the pointer on destruction. + //! It is reponsibility of the user to properly manage lifetime of the string. + //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - + //! on destruction of the document the string will be automatically freed. + //!

+ //! Size of name must be specified separately, because name does not have to be zero terminated. + //! Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated). + //! \param name Name of node to set. Does not have to be zero terminated. + //! \param size Size of name, in characters. This does not include zero terminator, if one is present. + void name(const Ch *name, std::size_t size) + { + m_name = const_cast(name); + m_name_size = size; + } + + //! Sets name of node to a zero-terminated string. + //! See also \ref ownership_of_strings and xml_node::name(const Ch *, std::size_t). + //! \param name Name of node to set. Must be zero terminated. + void name(const Ch *name) + { + this->name(name, internal::measure(name)); + } + + //! Sets value of node to a non zero-terminated string. + //! See \ref ownership_of_strings. + //!

+ //! Note that node does not own its name or value, it only stores a pointer to it. + //! It will not delete or otherwise free the pointer on destruction. + //! It is reponsibility of the user to properly manage lifetime of the string. + //! The easiest way to achieve it is to use memory_pool of the document to allocate the string - + //! on destruction of the document the string will be automatically freed. + //!

+ //! Size of value must be specified separately, because it does not have to be zero terminated. + //! Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated). + //!

+ //! If an element has a child node of type node_data, it will take precedence over element value when printing. + //! If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser. + //! \param value value of node to set. Does not have to be zero terminated. + //! \param size Size of value, in characters. This does not include zero terminator, if one is present. + void value(const Ch *value, std::size_t size) + { + m_value = const_cast(value); + m_value_size = size; + } + + //! Sets value of node to a zero-terminated string. + //! See also \ref ownership_of_strings and xml_node::value(const Ch *, std::size_t). + //! \param value Vame of node to set. Must be zero terminated. + void value(const Ch *value) + { + this->value(value, internal::measure(value)); + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets node parent. + //! \return Pointer to parent node, or 0 if there is no parent. + xml_node *parent() const + { + return m_parent; + } + + protected: + + // Return empty string + static Ch *nullstr() + { + static Ch zero = Ch('\0'); + return &zero; + } + + Ch *m_name; // Name of node, or 0 if no name + Ch *m_value; // Value of node, or 0 if no value + std::size_t m_name_size; // Length of node name, or undefined of no name + std::size_t m_value_size; // Length of node value, or undefined if no value + xml_node *m_parent; // Pointer to parent node, or 0 if none + + }; + + //! Class representing attribute node of XML document. + //! Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base). + //! Note that after parse, both name and value of attribute will point to interior of source text used for parsing. + //! Thus, this text must persist in memory for the lifetime of attribute. + //! \param Ch Character type to use. + template + class xml_attribute: public xml_base + { + + friend class xml_node; + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + //! Constructs an empty attribute with the specified type. + //! Consider using memory_pool of appropriate xml_document if allocating attributes manually. + xml_attribute() + { + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets document of which attribute is a child. + //! \return Pointer to document that contains this attribute, or 0 if there is no parent document. + xml_document *document() const + { + if (xml_node *node = this->parent()) + { + while (node->parent()) + node = node->parent(); + return node->type() == node_document ? static_cast *>(node) : 0; + } + else + return 0; + } + + //! Gets previous attribute, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *previous_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_prev_attribute; attribute; attribute = attribute->m_prev_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return this->m_parent ? m_prev_attribute : 0; + } + + //! Gets next attribute, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *next_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_next_attribute; attribute; attribute = attribute->m_next_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return this->m_parent ? m_next_attribute : 0; + } + + private: + + xml_attribute *m_prev_attribute; // Pointer to previous sibling of attribute, or 0 if none; only valid if parent is non-zero + xml_attribute *m_next_attribute; // Pointer to next sibling of attribute, or 0 if none; only valid if parent is non-zero + + }; + + /////////////////////////////////////////////////////////////////////////// + // XML node + + //! Class representing a node of XML document. + //! Each node may have associated name and value strings, which are available through name() and value() functions. + //! Interpretation of name and value depends on type of the node. + //! Type of node can be determined by using type() function. + //!

+ //! Note that after parse, both name and value of node, if any, will point interior of source text used for parsing. + //! Thus, this text must persist in the memory for the lifetime of node. + //! \param Ch Character type to use. + template + class xml_node: public xml_base + { + + public: + + /////////////////////////////////////////////////////////////////////////// + // Construction & destruction + + //! Constructs an empty node with the specified type. + //! Consider using memory_pool of appropriate document to allocate nodes manually. + //! \param type Type of node to construct. + xml_node(node_type type) + : m_type(type) + , m_first_node(0) + , m_first_attribute(0) + { + } + + /////////////////////////////////////////////////////////////////////////// + // Node data access + + //! Gets type of node. + //! \return Type of node. + node_type type() const + { + return m_type; + } + + /////////////////////////////////////////////////////////////////////////// + // Related nodes access + + //! Gets document of which node is a child. + //! \return Pointer to document that contains this node, or 0 if there is no parent document. + xml_document *document() const + { + xml_node *node = const_cast *>(this); + while (node->parent()) + node = node->parent(); + return node->type() == node_document ? static_cast *>(node) : 0; + } + + //! Gets first child node, optionally matching node name. + //! \param name Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found child, or 0 if not found. + xml_node *first_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *child = m_first_node; child; child = child->next_sibling()) + if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) + return child; + return 0; + } + else + return m_first_node; + } + + //! Gets last child node, optionally matching node name. + //! Behaviour is undefined if node has no children. + //! Use first_node() to test if node has children. + //! \param name Name of child to find, or 0 to return last child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found child, or 0 if not found. + xml_node *last_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + assert(m_first_node); // Cannot query for last child if node has no children + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *child = m_last_node; child; child = child->previous_sibling()) + if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive)) + return child; + return 0; + } + else + return m_last_node; + } + + //! Gets previous sibling node, optionally matching node name. + //! Behaviour is undefined if node has no parent. + //! Use parent() to test if node has a parent. + //! \param name Name of sibling to find, or 0 to return previous sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found sibling, or 0 if not found. + xml_node *previous_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + assert(this->m_parent); // Cannot query for siblings if node has no parent + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *sibling = m_prev_sibling; sibling; sibling = sibling->m_prev_sibling) + if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) + return sibling; + return 0; + } + else + return m_prev_sibling; + } + + //! Gets next sibling node, optionally matching node name. + //! Behaviour is undefined if node has no parent. + //! Use parent() to test if node has a parent. + //! \param name Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found sibling, or 0 if not found. + xml_node *next_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + assert(this->m_parent); // Cannot query for siblings if node has no parent + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_node *sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling) + if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive)) + return sibling; + return 0; + } + else + return m_next_sibling; + } + + //! Gets first attribute of node, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *first_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_first_attribute; attribute; attribute = attribute->m_next_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return m_first_attribute; + } + + //! Gets last attribute of node, optionally matching attribute name. + //! \param name Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero + //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string + //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters + //! \return Pointer to found attribute, or 0 if not found. + xml_attribute *last_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const + { + if (name) + { + if (name_size == 0) + name_size = internal::measure(name); + for (xml_attribute *attribute = m_last_attribute; attribute; attribute = attribute->m_prev_attribute) + if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive)) + return attribute; + return 0; + } + else + return m_first_attribute ? m_last_attribute : 0; + } + + /////////////////////////////////////////////////////////////////////////// + // Node modification + + //! Sets type of node. + //! \param type Type of node to set. + void type(node_type type) + { + m_type = type; + } + + /////////////////////////////////////////////////////////////////////////// + // Node manipulation + + //! Prepends a new child node. + //! The prepended child becomes the first child, and all existing children are moved one position back. + //! \param child Node to prepend. + void prepend_node(xml_node *child) + { + assert(child && !child->parent() && child->type() != node_document); + if (first_node()) + { + child->m_next_sibling = m_first_node; + m_first_node->m_prev_sibling = child; + } + else + { + child->m_next_sibling = 0; + m_last_node = child; + } + m_first_node = child; + child->m_parent = this; + child->m_prev_sibling = 0; + } + + //! Appends a new child node. + //! The appended child becomes the last child. + //! \param child Node to append. + void append_node(xml_node *child) + { + assert(child && !child->parent() && child->type() != node_document); + if (first_node()) + { + child->m_prev_sibling = m_last_node; + m_last_node->m_next_sibling = child; + } + else + { + child->m_prev_sibling = 0; + m_first_node = child; + } + m_last_node = child; + child->m_parent = this; + child->m_next_sibling = 0; + } + + //! Inserts a new child node at specified place inside the node. + //! All children after and including the specified node are moved one position back. + //! \param where Place where to insert the child, or 0 to insert at the back. + //! \param child Node to insert. + void insert_node(xml_node *where, xml_node *child) + { + assert(!where || where->parent() == this); + assert(child && !child->parent() && child->type() != node_document); + if (where == m_first_node) + prepend_node(child); + else if (where == 0) + append_node(child); + else + { + child->m_prev_sibling = where->m_prev_sibling; + child->m_next_sibling = where; + where->m_prev_sibling->m_next_sibling = child; + where->m_prev_sibling = child; + child->m_parent = this; + } + } + + //! Removes first child node. + //! If node has no children, behaviour is undefined. + //! Use first_node() to test if node has children. + void remove_first_node() + { + assert(first_node()); + xml_node *child = m_first_node; + m_first_node = child->m_next_sibling; + if (child->m_next_sibling) + child->m_next_sibling->m_prev_sibling = 0; + else + m_last_node = 0; + child->m_parent = 0; + } + + //! Removes last child of the node. + //! If node has no children, behaviour is undefined. + //! Use first_node() to test if node has children. + void remove_last_node() + { + assert(first_node()); + xml_node *child = m_last_node; + if (child->m_prev_sibling) + { + m_last_node = child->m_prev_sibling; + child->m_prev_sibling->m_next_sibling = 0; + } + else + m_first_node = 0; + child->m_parent = 0; + } + + //! Removes specified child from the node + // \param where Pointer to child to be removed. + void remove_node(xml_node *where) + { + assert(where && where->parent() == this); + assert(first_node()); + if (where == m_first_node) + remove_first_node(); + else if (where == m_last_node) + remove_last_node(); + else + { + where->m_prev_sibling->m_next_sibling = where->m_next_sibling; + where->m_next_sibling->m_prev_sibling = where->m_prev_sibling; + where->m_parent = 0; + } + } + + //! Removes all child nodes (but not attributes). + void remove_all_nodes() + { + for (xml_node *node = first_node(); node; node = node->m_next_sibling) + node->m_parent = 0; + m_first_node = 0; + } + + //! Prepends a new attribute to the node. + //! \param attribute Attribute to prepend. + void prepend_attribute(xml_attribute *attribute) + { + assert(attribute && !attribute->parent()); + if (first_attribute()) + { + attribute->m_next_attribute = m_first_attribute; + m_first_attribute->m_prev_attribute = attribute; + } + else + { + attribute->m_next_attribute = 0; + m_last_attribute = attribute; + } + m_first_attribute = attribute; + attribute->m_parent = this; + attribute->m_prev_attribute = 0; + } + + //! Appends a new attribute to the node. + //! \param attribute Attribute to append. + void append_attribute(xml_attribute *attribute) + { + assert(attribute && !attribute->parent()); + if (first_attribute()) + { + attribute->m_prev_attribute = m_last_attribute; + m_last_attribute->m_next_attribute = attribute; + } + else + { + attribute->m_prev_attribute = 0; + m_first_attribute = attribute; + } + m_last_attribute = attribute; + attribute->m_parent = this; + attribute->m_next_attribute = 0; + } + + //! Inserts a new attribute at specified place inside the node. + //! All attributes after and including the specified attribute are moved one position back. + //! \param where Place where to insert the attribute, or 0 to insert at the back. + //! \param attribute Attribute to insert. + void insert_attribute(xml_attribute *where, xml_attribute *attribute) + { + assert(!where || where->parent() == this); + assert(attribute && !attribute->parent()); + if (where == m_first_attribute) + prepend_attribute(attribute); + else if (where == 0) + append_attribute(attribute); + else + { + attribute->m_prev_attribute = where->m_prev_attribute; + attribute->m_next_attribute = where; + where->m_prev_attribute->m_next_attribute = attribute; + where->m_prev_attribute = attribute; + attribute->m_parent = this; + } + } + + //! Removes first attribute of the node. + //! If node has no attributes, behaviour is undefined. + //! Use first_attribute() to test if node has attributes. + void remove_first_attribute() + { + assert(first_attribute()); + xml_attribute *attribute = m_first_attribute; + if (attribute->m_next_attribute) + { + attribute->m_next_attribute->m_prev_attribute = 0; + } + else + m_last_attribute = 0; + attribute->m_parent = 0; + m_first_attribute = attribute->m_next_attribute; + } + + //! Removes last attribute of the node. + //! If node has no attributes, behaviour is undefined. + //! Use first_attribute() to test if node has attributes. + void remove_last_attribute() + { + assert(first_attribute()); + xml_attribute *attribute = m_last_attribute; + if (attribute->m_prev_attribute) + { + attribute->m_prev_attribute->m_next_attribute = 0; + m_last_attribute = attribute->m_prev_attribute; + } + else + m_first_attribute = 0; + attribute->m_parent = 0; + } + + //! Removes specified attribute from node. + //! \param where Pointer to attribute to be removed. + void remove_attribute(xml_attribute *where) + { + assert(first_attribute() && where->parent() == this); + if (where == m_first_attribute) + remove_first_attribute(); + else if (where == m_last_attribute) + remove_last_attribute(); + else + { + where->m_prev_attribute->m_next_attribute = where->m_next_attribute; + where->m_next_attribute->m_prev_attribute = where->m_prev_attribute; + where->m_parent = 0; + } + } + + //! Removes all attributes of node. + void remove_all_attributes() + { + for (xml_attribute *attribute = first_attribute(); attribute; attribute = attribute->m_next_attribute) + attribute->m_parent = 0; + m_first_attribute = 0; + } + + private: + + /////////////////////////////////////////////////////////////////////////// + // Restrictions + + // No copying + xml_node(const xml_node &); + void operator =(const xml_node &); + + /////////////////////////////////////////////////////////////////////////// + // Data members + + // Note that some of the pointers below have UNDEFINED values if certain other pointers are 0. + // This is required for maximum performance, as it allows the parser to omit initialization of + // unneded/redundant values. + // + // The rules are as follows: + // 1. first_node and first_attribute contain valid pointers, or 0 if node has no children/attributes respectively + // 2. last_node and last_attribute are valid only if node has at least one child/attribute respectively, otherwise they contain garbage + // 3. prev_sibling and next_sibling are valid only if node has a parent, otherwise they contain garbage + + node_type m_type; // Type of node; always valid + xml_node *m_first_node; // Pointer to first child node, or 0 if none; always valid + xml_node *m_last_node; // Pointer to last child node, or 0 if none; this value is only valid if m_first_node is non-zero + xml_attribute *m_first_attribute; // Pointer to first attribute of node, or 0 if none; always valid + xml_attribute *m_last_attribute; // Pointer to last attribute of node, or 0 if none; this value is only valid if m_first_attribute is non-zero + xml_node *m_prev_sibling; // Pointer to previous sibling of node, or 0 if none; this value is only valid if m_parent is non-zero + xml_node *m_next_sibling; // Pointer to next sibling of node, or 0 if none; this value is only valid if m_parent is non-zero + + }; + + /////////////////////////////////////////////////////////////////////////// + // XML document + + //! This class represents root of the DOM hierarchy. + //! It is also an xml_node and a memory_pool through public inheritance. + //! Use parse() function to build a DOM tree from a zero-terminated XML text string. + //! parse() function allocates memory for nodes and attributes by using functions of xml_document, + //! which are inherited from memory_pool. + //! To access root node of the document, use the document itself, as if it was an xml_node. + //! \param Ch Character type to use. + template + class xml_document: public xml_node, public memory_pool + { + + public: + + //! Constructs empty XML document + xml_document() + : xml_node(node_document) + { + } + + //! Parses zero-terminated XML string according to given flags. + //! Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used. + //! The string must persist for the lifetime of the document. + //! In case of error, rapidxml::parse_error exception will be thrown. + //!

+ //! If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning. + //! Make sure that data is zero-terminated. + //!

+ //! Document can be parsed into multiple times. + //! Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool. + //! \param text XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser. + template + void parse(Ch *text) + { + assert(text); + + // Remove current contents + this->remove_all_nodes(); + this->remove_all_attributes(); + + // Parse BOM, if any + parse_bom(text); + + // Parse children + while (1) + { + // Skip whitespace before node + skip(text); + if (*text == 0) + break; + + // Parse and append new child + if (*text == Ch('<')) + { + ++text; // Skip '<' + if (xml_node *node = parse_node(text)) + this->append_node(node); + } + else + RAPIDXML_PARSE_ERROR("expected <", text); + } + + } + + //! Clears the document by deleting all nodes and clearing the memory pool. + //! All nodes owned by document pool are destroyed. + void clear() + { + this->remove_all_nodes(); + this->remove_all_attributes(); + memory_pool::clear(); + } + + private: + + /////////////////////////////////////////////////////////////////////// + // Internal character utility functions + + // Detect whitespace character + struct whitespace_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_whitespace[static_cast(ch)]; + } + }; + + // Detect node name character + struct node_name_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_node_name[static_cast(ch)]; + } + }; + + // Detect attribute name character + struct attribute_name_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_attribute_name[static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) + struct text_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text[static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) that does not require processing + struct text_pure_no_ws_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text_pure_no_ws[static_cast(ch)]; + } + }; + + // Detect text character (PCDATA) that does not require processing + struct text_pure_with_ws_pred + { + static unsigned char test(Ch ch) + { + return internal::lookup_tables<0>::lookup_text_pure_with_ws[static_cast(ch)]; + } + }; + + // Detect attribute value character + template + struct attribute_value_pred + { + static unsigned char test(Ch ch) + { + if (Quote == Ch('\'')) + return internal::lookup_tables<0>::lookup_attribute_data_1[static_cast(ch)]; + if (Quote == Ch('\"')) + return internal::lookup_tables<0>::lookup_attribute_data_2[static_cast(ch)]; + return 0; // Should never be executed, to avoid warnings on Comeau + } + }; + + // Detect attribute value character + template + struct attribute_value_pure_pred + { + static unsigned char test(Ch ch) + { + if (Quote == Ch('\'')) + return internal::lookup_tables<0>::lookup_attribute_data_1_pure[static_cast(ch)]; + if (Quote == Ch('\"')) + return internal::lookup_tables<0>::lookup_attribute_data_2_pure[static_cast(ch)]; + return 0; // Should never be executed, to avoid warnings on Comeau + } + }; + + // Insert coded character, using UTF8 or 8-bit ASCII + template + static void insert_coded_character(Ch *&text, unsigned long code) + { + if (Flags & parse_no_utf8) + { + // Insert 8-bit ASCII character + // Todo: possibly verify that code is less than 256 and use replacement char otherwise? + text[0] = static_cast(code); + text += 1; + } + else + { + // Insert UTF8 sequence + if (code < 0x80) // 1 byte sequence + { + text[0] = static_cast(code); + text += 1; + } + else if (code < 0x800) // 2 byte sequence + { + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xC0); + text += 2; + } + else if (code < 0x10000) // 3 byte sequence + { + text[2] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xE0); + text += 3; + } + else if (code < 0x110000) // 4 byte sequence + { + text[3] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[2] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[1] = static_cast((code | 0x80) & 0xBF); code >>= 6; + text[0] = static_cast(code | 0xF0); + text += 4; + } + else // Invalid, only codes up to 0x10FFFF are allowed in Unicode + { + RAPIDXML_PARSE_ERROR("invalid numeric character entity", text); + } + } + } + + // Skip characters until predicate evaluates to true + template + static void skip(Ch *&text) + { + Ch *tmp = text; + while (StopPred::test(*tmp)) + ++tmp; + text = tmp; + } + + // Skip characters until predicate evaluates to true while doing the following: + // - replacing XML character entity references with proper characters (' & " < > &#...;) + // - condensing whitespace sequences to single space character + template + static Ch *skip_and_expand_character_refs(Ch *&text) + { + // If entity translation, whitespace condense and whitespace trimming is disabled, use plain skip + if (Flags & parse_no_entity_translation && + !(Flags & parse_normalize_whitespace) && + !(Flags & parse_trim_whitespace)) + { + skip(text); + return text; + } + + // Use simple skip until first modification is detected + skip(text); + + // Use translation skip + Ch *src = text; + Ch *dest = src; + while (StopPred::test(*src)) + { + // If entity translation is enabled + if (!(Flags & parse_no_entity_translation)) + { + // Test if replacement is needed + if (src[0] == Ch('&')) + { + switch (src[1]) + { + + // & ' + case Ch('a'): + if (src[2] == Ch('m') && src[3] == Ch('p') && src[4] == Ch(';')) + { + *dest = Ch('&'); + ++dest; + src += 5; + continue; + } + if (src[2] == Ch('p') && src[3] == Ch('o') && src[4] == Ch('s') && src[5] == Ch(';')) + { + *dest = Ch('\''); + ++dest; + src += 6; + continue; + } + break; + + // " + case Ch('q'): + if (src[2] == Ch('u') && src[3] == Ch('o') && src[4] == Ch('t') && src[5] == Ch(';')) + { + *dest = Ch('"'); + ++dest; + src += 6; + continue; + } + break; + + // > + case Ch('g'): + if (src[2] == Ch('t') && src[3] == Ch(';')) + { + *dest = Ch('>'); + ++dest; + src += 4; + continue; + } + break; + + // < + case Ch('l'): + if (src[2] == Ch('t') && src[3] == Ch(';')) + { + *dest = Ch('<'); + ++dest; + src += 4; + continue; + } + break; + + // &#...; - assumes ASCII + case Ch('#'): + if (src[2] == Ch('x')) + { + unsigned long code = 0; + src += 3; // Skip &#x + while (1) + { + unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast(*src)]; + if (digit == 0xFF) + break; + code = code * 16 + digit; + ++src; + } + insert_coded_character(dest, code); // Put character in output + } + else + { + unsigned long code = 0; + src += 2; // Skip &# + while (1) + { + unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast(*src)]; + if (digit == 0xFF) + break; + code = code * 10 + digit; + ++src; + } + insert_coded_character(dest, code); // Put character in output + } + if (*src == Ch(';')) + ++src; + else + RAPIDXML_PARSE_ERROR("expected ;", src); + continue; + + // Something else + default: + // Ignore, just copy '&' verbatim + break; + + } + } + } + + // If whitespace condensing is enabled + if (Flags & parse_normalize_whitespace) + { + // Test if condensing is needed + if (whitespace_pred::test(*src)) + { + *dest = Ch(' '); ++dest; // Put single space in dest + ++src; // Skip first whitespace char + // Skip remaining whitespace chars + while (whitespace_pred::test(*src)) + ++src; + continue; + } + } + + // No replacement, only copy character + *dest++ = *src++; + + } + + // Return new end + text = src; + return dest; + + } + + /////////////////////////////////////////////////////////////////////// + // Internal parsing functions + + // Parse BOM, if any + template + void parse_bom(Ch *&text) + { + // UTF-8? + if (static_cast(text[0]) == 0xEF && + static_cast(text[1]) == 0xBB && + static_cast(text[2]) == 0xBF) + { + text += 3; // Skup utf-8 bom + } + } + + // Parse XML declaration ( + xml_node *parse_xml_declaration(Ch *&text) + { + // If parsing of declaration is disabled + if (!(Flags & parse_declaration_node)) + { + // Skip until end of declaration + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 2; // Skip '?>' + return 0; + } + + // Create declaration + xml_node *declaration = this->allocate_node(node_declaration); + + // Skip whitespace before attributes or ?> + skip(text); + + // Parse declaration attributes + parse_node_attributes(text, declaration); + + // Skip ?> + if (text[0] != Ch('?') || text[1] != Ch('>')) + RAPIDXML_PARSE_ERROR("expected ?>", text); + text += 2; + + return declaration; + } + + // Parse XML comment (' + return 0; // Do not produce comment node + } + + // Remember value start + Ch *value = text; + + // Skip until end of comment + while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Create comment node + xml_node *comment = this->allocate_node(node_comment); + comment->value(value, text - value); + + // Place zero terminator after comment value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 3; // Skip '-->' + return comment; + } + + // Parse DOCTYPE + template + xml_node *parse_doctype(Ch *&text) + { + // Remember value start + Ch *value = text; + + // Skip to > + while (*text != Ch('>')) + { + // Determine character type + switch (*text) + { + + // If '[' encountered, scan for matching ending ']' using naive algorithm with depth + // This works for all W3C test files except for 2 most wicked + case Ch('['): + { + ++text; // Skip '[' + int depth = 1; + while (depth > 0) + { + switch (*text) + { + case Ch('['): ++depth; break; + case Ch(']'): --depth; break; + case 0: RAPIDXML_PARSE_ERROR("unexpected end of data", text); + } + ++text; + } + break; + } + + // Error on end of text + case Ch('\0'): + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + + // Other character, skip it + default: + ++text; + + } + } + + // If DOCTYPE nodes enabled + if (Flags & parse_doctype_node) + { + // Create a new doctype node + xml_node *doctype = this->allocate_node(node_doctype); + doctype->value(value, text - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 1; // skip '>' + return doctype; + } + else + { + text += 1; // skip '>' + return 0; + } + + } + + // Parse PI + template + xml_node *parse_pi(Ch *&text) + { + // If creation of PI nodes is enabled + if (Flags & parse_pi_nodes) + { + // Create pi node + xml_node *pi = this->allocate_node(node_pi); + + // Extract PI target name + Ch *name = text; + skip(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected PI target", text); + pi->name(name, text - name); + + // Skip whitespace between pi target and pi + skip(text); + + // Remember start of pi + Ch *value = text; + + // Skip to '?>' + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (*text == Ch('\0')) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Set pi value (verbatim, no entity expansion or whitespace normalization) + pi->value(value, text - value); + + // Place zero terminator after name and value + if (!(Flags & parse_no_string_terminators)) + { + pi->name()[pi->name_size()] = Ch('\0'); + pi->value()[pi->value_size()] = Ch('\0'); + } + + text += 2; // Skip '?>' + return pi; + } + else + { + // Skip to '?>' + while (text[0] != Ch('?') || text[1] != Ch('>')) + { + if (*text == Ch('\0')) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 2; // Skip '?>' + return 0; + } + } + + // Parse and append data + // Return character that ends data. + // This is necessary because this character might have been overwritten by a terminating 0 + template + Ch parse_and_append_data(xml_node *node, Ch *&text, Ch *contents_start) + { + // Backup to contents start if whitespace trimming is disabled + if (!(Flags & parse_trim_whitespace)) + text = contents_start; + + // Skip until end of data + Ch *value = text, *end; + if (Flags & parse_normalize_whitespace) + end = skip_and_expand_character_refs(text); + else + end = skip_and_expand_character_refs(text); + + // Trim trailing whitespace if flag is set; leading was already trimmed by whitespace skip after > + if (Flags & parse_trim_whitespace) + { + if (Flags & parse_normalize_whitespace) + { + // Whitespace is already condensed to single space characters by skipping function, so just trim 1 char off the end + if (*(end - 1) == Ch(' ')) + --end; + } + else + { + // Backup until non-whitespace character is found + while (whitespace_pred::test(*(end - 1))) + --end; + } + } + + // If characters are still left between end and value (this test is only necessary if normalization is enabled) + // Create new data node + if (!(Flags & parse_no_data_nodes)) + { + xml_node *data = this->allocate_node(node_data); + data->value(value, end - value); + node->append_node(data); + } + + // Add data to parent node if no data exists yet + if (!(Flags & parse_no_element_values)) + if (*node->value() == Ch('\0')) + node->value(value, end - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + { + Ch ch = *text; + *end = Ch('\0'); + return ch; // Return character that ends data; this is required because zero terminator overwritten it + } + + // Return character that ends data + return *text; + } + + // Parse CDATA + template + xml_node *parse_cdata(Ch *&text) + { + // If CDATA is disabled + if (Flags & parse_no_data_nodes) + { + // Skip until end of cdata + while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + text += 3; // Skip ]]> + return 0; // Do not produce CDATA node + } + + // Skip until end of cdata + Ch *value = text; + while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) + { + if (!text[0]) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + + // Create new cdata node + xml_node *cdata = this->allocate_node(node_cdata); + cdata->value(value, text - value); + + // Place zero terminator after value + if (!(Flags & parse_no_string_terminators)) + *text = Ch('\0'); + + text += 3; // Skip ]]> + return cdata; + } + + // Parse element node + template + xml_node *parse_element(Ch *&text) + { + // Create element node + xml_node *element = this->allocate_node(node_element); + + // Extract element name + Ch *name = text; + skip(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected element name", text); + element->name(name, text - name); + + // Skip whitespace between element name and attributes or > + skip(text); + + // Parse attributes, if any + parse_node_attributes(text, element); + + // Determine ending type + if (*text == Ch('>')) + { + ++text; + parse_node_contents(text, element); + } + else if (*text == Ch('/')) + { + ++text; + if (*text != Ch('>')) + RAPIDXML_PARSE_ERROR("expected >", text); + ++text; + } + else + RAPIDXML_PARSE_ERROR("expected >", text); + + // Place zero terminator after name + if (!(Flags & parse_no_string_terminators)) + element->name()[element->name_size()] = Ch('\0'); + + // Return parsed element + return element; + } + + // Determine node type, and parse it + template + xml_node *parse_node(Ch *&text) + { + // Parse proper node type + switch (text[0]) + { + + // <... + default: + // Parse and append element node + return parse_element(text); + + // (text); + } + else + { + // Parse PI + return parse_pi(text); + } + + // (text); + } + break; + + // (text); + } + break; + + // (text); + } + + } // switch + + // Attempt to skip other, unrecognized node types starting with ')) + { + if (*text == 0) + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + ++text; + } + ++text; // Skip '>' + return 0; // No node recognized + + } + } + + // Parse contents of the node - children, data etc. + template + void parse_node_contents(Ch *&text, xml_node *node) + { + // For all children and text + while (1) + { + // Skip whitespace between > and node contents + Ch *contents_start = text; // Store start of node contents before whitespace is skipped + skip(text); + Ch next_char = *text; + + // After data nodes, instead of continuing the loop, control jumps here. + // This is because zero termination inside parse_and_append_data() function + // would wreak havoc with the above code. + // Also, skipping whitespace after data nodes is unnecessary. + after_data_node: + + // Determine what comes next: node closing, child node, data node, or 0? + switch (next_char) + { + + // Node closing or child node + case Ch('<'): + if (text[1] == Ch('/')) + { + // Node closing + text += 2; // Skip '(text); + if (!internal::compare(node->name(), node->name_size(), closing_name, text - closing_name, true)) + RAPIDXML_PARSE_ERROR("invalid closing tag name", text); + } + else + { + // No validation, just skip name + skip(text); + } + // Skip remaining whitespace after node name + skip(text); + if (*text != Ch('>')) + RAPIDXML_PARSE_ERROR("expected >", text); + ++text; // Skip '>' + return; // Node closed, finished parsing contents + } + else + { + // Child node + ++text; // Skip '<' + if (xml_node *child = parse_node(text)) + node->append_node(child); + } + break; + + // End of data - error + case Ch('\0'): + RAPIDXML_PARSE_ERROR("unexpected end of data", text); + + // Data node + default: + next_char = parse_and_append_data(node, text, contents_start); + goto after_data_node; // Bypass regular processing after data nodes + + } + } + } + + // Parse XML attributes of the node + template + void parse_node_attributes(Ch *&text, xml_node *node) + { + // For all attributes + while (attribute_name_pred::test(*text)) + { + // Extract attribute name + Ch *name = text; + ++text; // Skip first character of attribute name + skip(text); + if (text == name) + RAPIDXML_PARSE_ERROR("expected attribute name", name); + + // Create new attribute + xml_attribute *attribute = this->allocate_attribute(); + attribute->name(name, text - name); + node->append_attribute(attribute); + + // Skip whitespace after attribute name + skip(text); + + // Skip = + if (*text != Ch('=')) + RAPIDXML_PARSE_ERROR("expected =", text); + ++text; + + // Add terminating zero after name + if (!(Flags & parse_no_string_terminators)) + attribute->name()[attribute->name_size()] = 0; + + // Skip whitespace after = + skip(text); + + // Skip quote and remember if it was ' or " + Ch quote = *text; + if (quote != Ch('\'') && quote != Ch('"')) + RAPIDXML_PARSE_ERROR("expected ' or \"", text); + ++text; + + // Extract attribute value and expand char refs in it + Ch *value = text, *end; + const int AttFlags = Flags & ~parse_normalize_whitespace; // No whitespace normalization in attributes + if (quote == Ch('\'')) + end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(text); + else + end = skip_and_expand_character_refs, attribute_value_pure_pred, AttFlags>(text); + + // Set attribute value + attribute->value(value, end - value); + + // Make sure that end quote is present + if (*text != quote) + RAPIDXML_PARSE_ERROR("expected ' or \"", text); + ++text; // Skip quote + + // Add terminating zero after value + if (!(Flags & parse_no_string_terminators)) + attribute->value()[attribute->value_size()] = 0; + + // Skip whitespace after attribute value + skip(text); + } + } + + }; + + //! \cond internal + namespace internal + { + + // Whitespace (space \n \r \t) + template + const unsigned char lookup_tables::lookup_whitespace[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, // 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1 + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F + }; + + // Node name (anything but space \n \r \t / > ? \0) + template + const unsigned char lookup_tables::lookup_node_name[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) (anything but < \0) + template + const unsigned char lookup_tables::lookup_text[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) that does not require processing when ws normalization is disabled + // (anything but < \0 &) + template + const unsigned char lookup_tables::lookup_text_pure_no_ws[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Text (i.e. PCDATA) that does not require processing when ws normalizationis is enabled + // (anything but < \0 & space \n \r \t) + template + const unsigned char lookup_tables::lookup_text_pure_with_ws[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute name (anything but space \n \r \t / < > = ? ! \0) + template + const unsigned char lookup_tables::lookup_attribute_name[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with single quote (anything but ' \0) + template + const unsigned char lookup_tables::lookup_attribute_data_1[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with single quote that does not require processing (anything but ' \0 &) + template + const unsigned char lookup_tables::lookup_attribute_data_1_pure[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with double quote (anything but " \0) + template + const unsigned char lookup_tables::lookup_attribute_data_2[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Attribute data with double quote that does not require processing (anything but " \0 &) + template + const unsigned char lookup_tables::lookup_attribute_data_2_pure[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1 + 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F + }; + + // Digits (dec and hex, 255 denotes end of numeric character reference) + template + const unsigned char lookup_tables::lookup_digits[256] = + { + // 0 1 2 3 4 5 6 7 8 9 A B C D E F + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 0 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 1 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 2 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,255,255,255,255,255,255, // 3 + 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 4 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 5 + 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 6 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 7 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 8 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 9 + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // A + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // B + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // C + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // D + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // E + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 // F + }; + + // Upper case conversion + template + const unsigned char lookup_tables::lookup_upcase[256] = + { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A B C D E F + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 0 + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, // 1 + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // 2 + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // 3 + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 4 + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, // 5 + 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 6 + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123,124,125,126,127, // 7 + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 8 + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, // 9 + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // A + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, // B + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // C + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // D + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // E + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // F + }; + } + //! \endcond + +} + +// Undefine internal macros +#undef RAPIDXML_PARSE_ERROR + +// On MSVC, restore warnings state +#ifdef _MSC_VER + #pragma warning(pop) +#endif + +#endif diff --git a/rapidxml-1.13/rapidxml_iterators.hpp b/rapidxml-1.13/rapidxml_iterators.hpp new file mode 100644 index 0000000..85c5894 --- /dev/null +++ b/rapidxml-1.13/rapidxml_iterators.hpp @@ -0,0 +1,174 @@ +#ifndef RAPIDXML_ITERATORS_HPP_INCLUDED +#define RAPIDXML_ITERATORS_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml_iterators.hpp This file contains rapidxml iterators + +#include "rapidxml.hpp" + +namespace rapidxml +{ + + //! Iterator of child nodes of xml_node + template + class node_iterator + { + + public: + + typedef typename xml_node value_type; + typedef typename xml_node &reference; + typedef typename xml_node *pointer; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + node_iterator() + : m_node(0) + { + } + + node_iterator(xml_node *node) + : m_node(node->first_node()) + { + } + + reference operator *() const + { + assert(m_node); + return *m_node; + } + + pointer operator->() const + { + assert(m_node); + return m_node; + } + + node_iterator& operator++() + { + assert(m_node); + m_node = m_node->next_sibling(); + return *this; + } + + node_iterator operator++(int) + { + node_iterator tmp = *this; + ++this; + return tmp; + } + + node_iterator& operator--() + { + assert(m_node && m_node->previous_sibling()); + m_node = m_node->previous_sibling(); + return *this; + } + + node_iterator operator--(int) + { + node_iterator tmp = *this; + ++this; + return tmp; + } + + bool operator ==(const node_iterator &rhs) + { + return m_node == rhs.m_node; + } + + bool operator !=(const node_iterator &rhs) + { + return m_node != rhs.m_node; + } + + private: + + xml_node *m_node; + + }; + + //! Iterator of child attributes of xml_node + template + class attribute_iterator + { + + public: + + typedef typename xml_attribute value_type; + typedef typename xml_attribute &reference; + typedef typename xml_attribute *pointer; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + attribute_iterator() + : m_attribute(0) + { + } + + attribute_iterator(xml_node *node) + : m_attribute(node->first_attribute()) + { + } + + reference operator *() const + { + assert(m_attribute); + return *m_attribute; + } + + pointer operator->() const + { + assert(m_attribute); + return m_attribute; + } + + attribute_iterator& operator++() + { + assert(m_attribute); + m_attribute = m_attribute->next_attribute(); + return *this; + } + + attribute_iterator operator++(int) + { + attribute_iterator tmp = *this; + ++this; + return tmp; + } + + attribute_iterator& operator--() + { + assert(m_attribute && m_attribute->previous_attribute()); + m_attribute = m_attribute->previous_attribute(); + return *this; + } + + attribute_iterator operator--(int) + { + attribute_iterator tmp = *this; + ++this; + return tmp; + } + + bool operator ==(const attribute_iterator &rhs) + { + return m_attribute == rhs.m_attribute; + } + + bool operator !=(const attribute_iterator &rhs) + { + return m_attribute != rhs.m_attribute; + } + + private: + + xml_attribute *m_attribute; + + }; + +} + +#endif diff --git a/rapidxml-1.13/rapidxml_print.hpp b/rapidxml-1.13/rapidxml_print.hpp new file mode 100644 index 0000000..d03d5f5 --- /dev/null +++ b/rapidxml-1.13/rapidxml_print.hpp @@ -0,0 +1,421 @@ +#ifndef RAPIDXML_PRINT_HPP_INCLUDED +#define RAPIDXML_PRINT_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml_print.hpp This file contains rapidxml printer implementation + +#include "rapidxml.hpp" + +// Only include streams if not disabled +#ifndef RAPIDXML_NO_STREAMS + #include + #include +#endif + +namespace rapidxml +{ + + /////////////////////////////////////////////////////////////////////// + // Printing flags + + const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function. + + /////////////////////////////////////////////////////////////////////// + // Internal + + //! \cond internal + namespace internal + { + + /////////////////////////////////////////////////////////////////////////// + // Internal character operations + + // Copy characters from given range to given output iterator + template + inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out) + { + while (begin != end) + *out++ = *begin++; + return out; + } + + // Copy characters from given range to given output iterator and expand + // characters into references (< > ' " &) + template + inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out) + { + while (begin != end) + { + if (*begin == noexpand) + { + *out++ = *begin; // No expansion, copy character + } + else + { + switch (*begin) + { + case Ch('<'): + *out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';'); + break; + case Ch('>'): + *out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';'); + break; + case Ch('\''): + *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';'); + break; + case Ch('"'): + *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';'); + break; + case Ch('&'): + *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';'); + break; + default: + *out++ = *begin; // No expansion, copy character + } + } + ++begin; // Step to next character + } + return out; + } + + // Fill given output iterator with repetitions of the same character + template + inline OutIt fill_chars(OutIt out, int n, Ch ch) + { + for (int i = 0; i < n; ++i) + *out++ = ch; + return out; + } + + // Find character + template + inline bool find_char(const Ch *begin, const Ch *end) + { + while (begin != end) + if (*begin++ == ch) + return true; + return false; + } + + /////////////////////////////////////////////////////////////////////////// + // Internal printing operations + + // Print node + template + inline OutIt print_node(OutIt out, const xml_node *node, int flags, int indent) + { + // Print proper node type + switch (node->type()) + { + + // Document + case node_document: + out = print_children(out, node, flags, indent); + break; + + // Element + case node_element: + out = print_element_node(out, node, flags, indent); + break; + + // Data + case node_data: + out = print_data_node(out, node, flags, indent); + break; + + // CDATA + case node_cdata: + out = print_cdata_node(out, node, flags, indent); + break; + + // Declaration + case node_declaration: + out = print_declaration_node(out, node, flags, indent); + break; + + // Comment + case node_comment: + out = print_comment_node(out, node, flags, indent); + break; + + // Doctype + case node_doctype: + out = print_doctype_node(out, node, flags, indent); + break; + + // Pi + case node_pi: + out = print_pi_node(out, node, flags, indent); + break; + + // Unknown + default: + assert(0); + break; + } + + // If indenting not disabled, add line break after node + if (!(flags & print_no_indenting)) + *out = Ch('\n'), ++out; + + // Return modified iterator + return out; + } + + // Print children of the node + template + inline OutIt print_children(OutIt out, const xml_node *node, int flags, int indent) + { + for (xml_node *child = node->first_node(); child; child = child->next_sibling()) + out = print_node(out, child, flags, indent); + return out; + } + + // Print attributes of the node + template + inline OutIt print_attributes(OutIt out, const xml_node *node, int flags) + { + for (xml_attribute *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute()) + { + if (attribute->name() && attribute->value()) + { + // Print attribute name + *out = Ch(' '), ++out; + out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out); + *out = Ch('='), ++out; + // Print attribute value using appropriate quote type + if (find_char(attribute->value(), attribute->value() + attribute->value_size())) + { + *out = Ch('\''), ++out; + out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out); + *out = Ch('\''), ++out; + } + else + { + *out = Ch('"'), ++out; + out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out); + *out = Ch('"'), ++out; + } + } + } + return out; + } + + // Print data node + template + inline OutIt print_data_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_data); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); + return out; + } + + // Print data node + template + inline OutIt print_cdata_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_cdata); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'); ++out; + *out = Ch('!'); ++out; + *out = Ch('['); ++out; + *out = Ch('C'); ++out; + *out = Ch('D'); ++out; + *out = Ch('A'); ++out; + *out = Ch('T'); ++out; + *out = Ch('A'); ++out; + *out = Ch('['); ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch(']'); ++out; + *out = Ch(']'); ++out; + *out = Ch('>'); ++out; + return out; + } + + // Print element node + template + inline OutIt print_element_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_element); + + // Print element name and attributes, if any + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + out = print_attributes(out, node, flags); + + // If node is childless + if (node->value_size() == 0 && !node->first_node()) + { + // Print childless node tag ending + *out = Ch('/'), ++out; + *out = Ch('>'), ++out; + } + else + { + // Print normal node tag ending + *out = Ch('>'), ++out; + + // Test if node contains a single data node only (and no other nodes) + xml_node *child = node->first_node(); + if (!child) + { + // If node has no children, only print its value without indenting + out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out); + } + else if (child->next_sibling() == 0 && child->type() == node_data) + { + // If node has a sole data child, only print its value without indenting + out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out); + } + else + { + // Print all children with full indenting + if (!(flags & print_no_indenting)) + *out = Ch('\n'), ++out; + out = print_children(out, node, flags, indent + 1); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + } + + // Print node end + *out = Ch('<'), ++out; + *out = Ch('/'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + *out = Ch('>'), ++out; + } + return out; + } + + // Print declaration node + template + inline OutIt print_declaration_node(OutIt out, const xml_node *node, int flags, int indent) + { + // Print declaration start + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('?'), ++out; + *out = Ch('x'), ++out; + *out = Ch('m'), ++out; + *out = Ch('l'), ++out; + + // Print attributes + out = print_attributes(out, node, flags); + + // Print declaration end + *out = Ch('?'), ++out; + *out = Ch('>'), ++out; + + return out; + } + + // Print comment node + template + inline OutIt print_comment_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_comment); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('!'), ++out; + *out = Ch('-'), ++out; + *out = Ch('-'), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('-'), ++out; + *out = Ch('-'), ++out; + *out = Ch('>'), ++out; + return out; + } + + // Print doctype node + template + inline OutIt print_doctype_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_doctype); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('!'), ++out; + *out = Ch('D'), ++out; + *out = Ch('O'), ++out; + *out = Ch('C'), ++out; + *out = Ch('T'), ++out; + *out = Ch('Y'), ++out; + *out = Ch('P'), ++out; + *out = Ch('E'), ++out; + *out = Ch(' '), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('>'), ++out; + return out; + } + + // Print pi node + template + inline OutIt print_pi_node(OutIt out, const xml_node *node, int flags, int indent) + { + assert(node->type() == node_pi); + if (!(flags & print_no_indenting)) + out = fill_chars(out, indent, Ch('\t')); + *out = Ch('<'), ++out; + *out = Ch('?'), ++out; + out = copy_chars(node->name(), node->name() + node->name_size(), out); + *out = Ch(' '), ++out; + out = copy_chars(node->value(), node->value() + node->value_size(), out); + *out = Ch('?'), ++out; + *out = Ch('>'), ++out; + return out; + } + + } + //! \endcond + + /////////////////////////////////////////////////////////////////////////// + // Printing + + //! Prints XML to given output iterator. + //! \param out Output iterator to print to. + //! \param node Node to be printed. Pass xml_document to print entire document. + //! \param flags Flags controlling how XML is printed. + //! \return Output iterator pointing to position immediately after last character of printed text. + template + inline OutIt print(OutIt out, const xml_node &node, int flags = 0) + { + return internal::print_node(out, &node, flags, 0); + } + +#ifndef RAPIDXML_NO_STREAMS + + //! Prints XML to given output stream. + //! \param out Output stream to print to. + //! \param node Node to be printed. Pass xml_document to print entire document. + //! \param flags Flags controlling how XML is printed. + //! \return Output stream. + template + inline std::basic_ostream &print(std::basic_ostream &out, const xml_node &node, int flags = 0) + { + print(std::ostream_iterator(out), node, flags); + return out; + } + + //! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process. + //! \param out Output stream to print to. + //! \param node Node to be printed. + //! \return Output stream. + template + inline std::basic_ostream &operator <<(std::basic_ostream &out, const xml_node &node) + { + return print(out, node); + } + +#endif + +} + +#endif diff --git a/rapidxml-1.13/rapidxml_utils.hpp b/rapidxml-1.13/rapidxml_utils.hpp new file mode 100644 index 0000000..5eafa35 --- /dev/null +++ b/rapidxml-1.13/rapidxml_utils.hpp @@ -0,0 +1,122 @@ +#ifndef RAPIDXML_UTILS_HPP_INCLUDED +#define RAPIDXML_UTILS_HPP_INCLUDED + +// Copyright (C) 2006, 2009 Marcin Kalicinski +// Version 1.13 +// Revision $DateTime: 2009/05/13 01:46:17 $ +//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful +//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective. + +#include "rapidxml.hpp" +#include +#include +#include +#include + +namespace rapidxml +{ + + //! Represents data loaded from a file + template + class file + { + + public: + + //! Loads file into the memory. Data will be automatically destroyed by the destructor. + //! \param filename Filename to load. + file(const char *filename) + { + using namespace std; + + // Open stream + basic_ifstream stream(filename, ios::binary); + if (!stream) + throw runtime_error(string("cannot open file ") + filename); + stream.unsetf(ios::skipws); + + // Determine stream size + stream.seekg(0, ios::end); + size_t size = stream.tellg(); + stream.seekg(0); + + // Load data and add terminating 0 + m_data.resize(size + 1); + stream.read(&m_data.front(), static_cast(size)); + m_data[size] = 0; + } + + //! Loads file into the memory. Data will be automatically destroyed by the destructor + //! \param stream Stream to load from + file(std::basic_istream &stream) + { + using namespace std; + + // Load data and add terminating 0 + stream.unsetf(ios::skipws); + m_data.assign(istreambuf_iterator(stream), istreambuf_iterator()); + if (stream.fail() || stream.bad()) + throw runtime_error("error reading stream"); + m_data.push_back(0); + } + + //! Gets file data. + //! \return Pointer to data of file. + Ch *data() + { + return &m_data.front(); + } + + //! Gets file data. + //! \return Pointer to data of file. + const Ch *data() const + { + return &m_data.front(); + } + + //! Gets file data size. + //! \return Size of file data, in characters. + std::size_t size() const + { + return m_data.size(); + } + + private: + + std::vector m_data; // File data + + }; + + //! Counts children of node. Time complexity is O(n). + //! \return Number of children of node + template + inline std::size_t count_children(xml_node *node) + { + xml_node *child = node->first_node(); + std::size_t count = 0; + while (child) + { + ++count; + child = child->next_sibling(); + } + return count; + } + + //! Counts attributes of node. Time complexity is O(n). + //! \return Number of attributes of node + template + inline std::size_t count_attributes(xml_node *node) + { + xml_attribute *attr = node->first_attribute(); + std::size_t count = 0; + while (attr) + { + ++count; + attr = attr->next_attribute(); + } + return count; + } + +} + +#endif diff --git a/rapidxml.cpp b/rapidxml.cpp new file mode 100644 index 0000000..9204007 --- /dev/null +++ b/rapidxml.cpp @@ -0,0 +1,81 @@ +/* +** -*- coding: utf-8 -*- +** +** File: rapidxml.cpp +** by Arzaroth Lekva +** arzaroth@arzaroth.com +** +*/ + +#include +#include + +struct module_state { + PyObject *error; +}; + +#if PY_MAJOR_VERSION >= 3 +# define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) +#else +# define GETSTATE(m) (&_state) +static struct module_state _state; +#endif + +static PyMethodDef module_funcs[] = { + {NULL, NULL} +}; + +#if PY_MAJOR_VERSION >= 3 + +static int module_traverse(PyObject* m, visitproc visit, void* arg) { + Py_VISIT(GETSTATE(m)->error); + return 0; +} + +static int module_clear(PyObject* m) { + Py_CLEAR(GETSTATE(m)->error); + return 0; +} + +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "rapidxml", + NULL, + sizeof(struct module_state), + module_funcs, + NULL, + module_traverse, + module_clear, + NULL +}; + +# define INITERROR return NULL + +PyMODINIT_FUNC PyInit_rapidxml(void) + +#else +# define INITERROR return + +PyMODINIT_FUNC initrapidxml(void) +#endif +{ +#if PY_MAJOR_VERSION >= 3 + PyObject* module = PyModule_Create(&moduledef); +#else + PyObject* module = Py_InitModule("rapidxml", module_funcs); +#endif + + if (module == NULL) + INITERROR; + struct module_state* st = GETSTATE(module); + + st->error = PyErr_NewException("rapidxml.Error", NULL, NULL); + if (st->error == NULL) { + Py_DECREF(module); + INITERROR; + } + +#if PY_MAJOR_VERSION >= 3 + return module; +#endif +} diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..7a7c3bc --- /dev/null +++ b/setup.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# File: setup.py +# by Arzaroth Lekva +# arzaroth@arzaroth.com +# + +from setuptools import setup, Extension + +rapidxml = Extension("rapidxml", + define_macros=[('MAJOR_VERSION', '1', + 'MINOR_VERSION', '0')], + include_dirs=['./rapidxml-1.13/'], + sources=["rapidxml.cpp"], +) + +setup( + ext_modules=[rapidxml], + name='RapidXml', + version='1.0', + license='MIT', + + author='Marc-Etienne Barrut', + author_email='lekva@arzaroth.com', + + description='python bindings for RapidXml, a C++ XML parsing library', + keywords='rapidxml xml parsing', +) From cf75bb325c9348cf6990e63b915dacec2937739f Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Sat, 11 Apr 2015 11:37:39 +0900 Subject: [PATCH 003/101] rapidxml object --- rapidxml.cpp | 59 +++++++++++++++++++++++++++++++++++++++++++++------- setup.py | 4 ++-- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/rapidxml.cpp b/rapidxml.cpp index 9204007..f776215 100644 --- a/rapidxml.cpp +++ b/rapidxml.cpp @@ -21,8 +21,43 @@ struct module_state { static struct module_state _state; #endif -static PyMethodDef module_funcs[] = { - {NULL, NULL} +#define MODULE_DESC "rapidxml module for rapidxml bindings" + +typedef struct { + PyObject_HEAD +} rapidxml_RapidXmlObject; + +static PyTypeObject rapidxml_RapidXmlType = { + #if PY_MAJOR_VERSION >= 3 + PyVarObject_HEAD_INIT(NULL, 0) + #else + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + #endif + "rapidxml.RapidXml", /*tp_name*/ + sizeof(rapidxml_RapidXmlObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_reserved*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "RapidXml objects", /* tp_doc */ +}; + +static PyMethodDef rapidxml_methods[] = { + {NULL} }; #if PY_MAJOR_VERSION >= 3 @@ -40,9 +75,9 @@ static int module_clear(PyObject* m) { static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "rapidxml", - NULL, + MODULE_DESC, sizeof(struct module_state), - module_funcs, + rapidxml_methods, NULL, module_traverse, module_clear, @@ -59,22 +94,30 @@ PyMODINIT_FUNC PyInit_rapidxml(void) PyMODINIT_FUNC initrapidxml(void) #endif { + PyObject* module; + + rapidxml_RapidXmlType.tp_new = PyType_GenericNew; + if (PyType_Ready(&rapidxml_RapidXmlType) < 0) + INITERROR; + #if PY_MAJOR_VERSION >= 3 - PyObject* module = PyModule_Create(&moduledef); + module = PyModule_Create(&moduledef); #else - PyObject* module = Py_InitModule("rapidxml", module_funcs); + module = Py_InitModule3("rapidxml", rapidxml_methods, MODULE_DESC); #endif - if (module == NULL) INITERROR; - struct module_state* st = GETSTATE(module); + struct module_state* st = GETSTATE(module); st->error = PyErr_NewException("rapidxml.Error", NULL, NULL); if (st->error == NULL) { Py_DECREF(module); INITERROR; } + Py_INCREF(&rapidxml_RapidXmlType); + PyModule_AddObject(module, "RapidXml", (PyObject *)&rapidxml_RapidXmlType); + #if PY_MAJOR_VERSION >= 3 return module; #endif diff --git a/setup.py b/setup.py index 7a7c3bc..12c5d01 100644 --- a/setup.py +++ b/setup.py @@ -9,8 +9,8 @@ from setuptools import setup, Extension rapidxml = Extension("rapidxml", - define_macros=[('MAJOR_VERSION', '1', - 'MINOR_VERSION', '0')], + define_macros=[('MAJOR_VERSION', '1'), + ('MINOR_VERSION', '0')], include_dirs=['./rapidxml-1.13/'], sources=["rapidxml.cpp"], ) From 007128f24e8fd46f0ce487e029a58cc0babf709d Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Sat, 11 Apr 2015 13:44:51 +0900 Subject: [PATCH 004/101] such macro --- rapidxml.cpp | 46 +++++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/rapidxml.cpp b/rapidxml.cpp index f776215..07d5d28 100644 --- a/rapidxml.cpp +++ b/rapidxml.cpp @@ -10,6 +10,11 @@ #include #include +#define STR(x) #x +#define STRINGIFY(x) STR(x) +#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__) +#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__ + struct module_state { PyObject *error; }; @@ -22,20 +27,26 @@ static struct module_state _state; #endif #define MODULE_DESC "rapidxml module for rapidxml bindings" +#define MODULE_NAME rapidxml +#define OBJ_NAME RapidXml + +#define OBJ_TYPE CAT(MODULE_NAME, CAT(_, CAT(OBJ_NAME, Type))) +#define OBJ_OBJECT CAT(MODULE_NAME, CAT(_, CAT(OBJ_NAME, Object))) +#define MODULE_METHS CAT(MODULE_NAME, _methods) typedef struct { PyObject_HEAD -} rapidxml_RapidXmlObject; +} OBJ_OBJECT; -static PyTypeObject rapidxml_RapidXmlType = { +static PyTypeObject OBJ_TYPE = { #if PY_MAJOR_VERSION >= 3 PyVarObject_HEAD_INIT(NULL, 0) #else PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ #endif - "rapidxml.RapidXml", /*tp_name*/ - sizeof(rapidxml_RapidXmlObject), /*tp_basicsize*/ + STRINGIFY(MODULE_NAME) "." STRINGIFY(OBJ_NAME), /*tp_name*/ + sizeof(OBJ_OBJECT), /*tp_basicsize*/ 0, /*tp_itemsize*/ 0, /*tp_dealloc*/ 0, /*tp_print*/ @@ -56,7 +67,7 @@ static PyTypeObject rapidxml_RapidXmlType = { "RapidXml objects", /* tp_doc */ }; -static PyMethodDef rapidxml_methods[] = { +static PyMethodDef MODULE_METHS[] = { {NULL} }; @@ -74,10 +85,10 @@ static int module_clear(PyObject* m) { static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, - "rapidxml", + STRINGIFY(MODULE_NAME), MODULE_DESC, sizeof(struct module_state), - rapidxml_methods, + MODULE_METHS, NULL, module_traverse, module_clear, @@ -86,37 +97,42 @@ static struct PyModuleDef moduledef = { # define INITERROR return NULL -PyMODINIT_FUNC PyInit_rapidxml(void) +PyMODINIT_FUNC CAT(PyInit_, MODULE_NAME)(void) #else # define INITERROR return -PyMODINIT_FUNC initrapidxml(void) +PyMODINIT_FUNC CAT(init, MODULE_NAME)(void) #endif { PyObject* module; - rapidxml_RapidXmlType.tp_new = PyType_GenericNew; - if (PyType_Ready(&rapidxml_RapidXmlType) < 0) + OBJ_TYPE.tp_new = PyType_GenericNew; + if (PyType_Ready(&OBJ_TYPE) < 0) INITERROR; #if PY_MAJOR_VERSION >= 3 module = PyModule_Create(&moduledef); #else - module = Py_InitModule3("rapidxml", rapidxml_methods, MODULE_DESC); + module = Py_InitModule3(STRINGIFY(MODULE_NAME), + MODULE_METHS, + MODULE_DESC); #endif if (module == NULL) INITERROR; struct module_state* st = GETSTATE(module); - st->error = PyErr_NewException("rapidxml.Error", NULL, NULL); + st->error = PyErr_NewException(STRINGIFY(MODULE_NAME) ".Error", + NULL, NULL); if (st->error == NULL) { Py_DECREF(module); INITERROR; } - Py_INCREF(&rapidxml_RapidXmlType); - PyModule_AddObject(module, "RapidXml", (PyObject *)&rapidxml_RapidXmlType); + Py_INCREF(&OBJ_TYPE); + PyModule_AddObject(module, + STRINGIFY(OBJ_NAME), + (PyObject *)&OBJ_TYPE); #if PY_MAJOR_VERSION >= 3 return module; From 26cf8243c7effb68fb9206bc1b91fafbc5bc03fd Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Sat, 11 Apr 2015 16:21:36 +0900 Subject: [PATCH 005/101] init & parse --- rapidxml.cpp | 156 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 103 insertions(+), 53 deletions(-) diff --git a/rapidxml.cpp b/rapidxml.cpp index 07d5d28..5ef1ac3 100644 --- a/rapidxml.cpp +++ b/rapidxml.cpp @@ -8,6 +8,7 @@ */ #include +#include #include #define STR(x) #x @@ -19,52 +20,113 @@ struct module_state { PyObject *error; }; -#if PY_MAJOR_VERSION >= 3 -# define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) -#else -# define GETSTATE(m) (&_state) -static struct module_state _state; -#endif - #define MODULE_DESC "rapidxml module for rapidxml bindings" #define MODULE_NAME rapidxml -#define OBJ_NAME RapidXml - -#define OBJ_TYPE CAT(MODULE_NAME, CAT(_, CAT(OBJ_NAME, Type))) -#define OBJ_OBJECT CAT(MODULE_NAME, CAT(_, CAT(OBJ_NAME, Object))) #define MODULE_METHS CAT(MODULE_NAME, _methods) +#define OBJECT_NAME RapidXml +#define OBJ_TYPE CAT(MODULE_NAME, CAT(_, CAT(OBJECT_NAME, Type))) +#define OBJ_OBJECT CAT(MODULE_NAME, CAT(_, CAT(OBJECT_NAME, Object))) +#define OBJ_METHS CAT(OBJECT_NAME, _methods) +#define OBJ_MEMBERS CAT(OBJECT_NAME, _members) + +#define EXCEPT_NAME CAT(OBJECT_NAME, Error) + +static PyObject* EXCEPT_NAME; + typedef struct { PyObject_HEAD + rapidxml::xml_document<> doc; } OBJ_OBJECT; +static void CAT(OBJECT_NAME, _dealloc)(OBJ_OBJECT* self) { + #if PY_MAJOR_VERSION >= 3 + Py_TYPE(self)->tp_free((PyObject*)self); + #else + self->ob_type->tp_free((PyObject*)self); + #endif +} + +static PyObject* CAT(OBJECT_NAME, _new)(PyTypeObject* type, + PyObject* args, + PyObject* kwds) { + OBJ_OBJECT* self; + + self = (OBJ_OBJECT*)type->tp_alloc(type, 0); + return (PyObject*)self; +} + +static int CAT(OBJECT_NAME, _init)(OBJ_OBJECT* self, + PyObject* args, + PyObject* kwds) { + char* text; + + static char* kwlist[] = {"text", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, + &text)) { + return -1; + } + try { + self->doc.parse<0>(text); + } catch (rapidxml::parse_error &e) { + PyErr_SetString(EXCEPT_NAME, e.what()); + return -1; + } + return 0; +} + +static PyMemberDef OBJ_MEMBERS[] = { + {NULL} +}; + +static PyMethodDef OBJ_METHS[] = { + {NULL} +}; + static PyTypeObject OBJ_TYPE = { #if PY_MAJOR_VERSION >= 3 PyVarObject_HEAD_INIT(NULL, 0) #else PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ + 0, /* ob_size */ #endif - STRINGIFY(MODULE_NAME) "." STRINGIFY(OBJ_NAME), /*tp_name*/ - sizeof(OBJ_OBJECT), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - 0, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_reserved*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ + STRINGIFY(MODULE_NAME) "." STRINGIFY(OBJECT_NAME), /* tp_name */ + sizeof(OBJ_OBJECT), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)CAT(OBJECT_NAME, _dealloc), /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ "RapidXml objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + OBJ_METHS, /* tp_methods */ + OBJ_MEMBERS, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)CAT(OBJECT_NAME, _init), /* tp_init */ + 0, /* tp_alloc */ + CAT(OBJECT_NAME, _new), /* tp_new */ }; static PyMethodDef MODULE_METHS[] = { @@ -73,25 +135,15 @@ static PyMethodDef MODULE_METHS[] = { #if PY_MAJOR_VERSION >= 3 -static int module_traverse(PyObject* m, visitproc visit, void* arg) { - Py_VISIT(GETSTATE(m)->error); - return 0; -} - -static int module_clear(PyObject* m) { - Py_CLEAR(GETSTATE(m)->error); - return 0; -} - static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, STRINGIFY(MODULE_NAME), MODULE_DESC, - sizeof(struct module_state), + -1, MODULE_METHS, NULL, - module_traverse, - module_clear, + NULL, + NULL, NULL }; @@ -121,19 +173,17 @@ PyMODINIT_FUNC CAT(init, MODULE_NAME)(void) if (module == NULL) INITERROR; - struct module_state* st = GETSTATE(module); - st->error = PyErr_NewException(STRINGIFY(MODULE_NAME) ".Error", - NULL, NULL); - if (st->error == NULL) { - Py_DECREF(module); - INITERROR; - } - Py_INCREF(&OBJ_TYPE); PyModule_AddObject(module, - STRINGIFY(OBJ_NAME), + STRINGIFY(OBJECT_NAME), (PyObject *)&OBJ_TYPE); + EXCEPT_NAME = PyErr_NewException(STRINGIFY(MODULE_NAME) "." STRINGIFY(EXCEPT_NAME), + NULL, NULL); + Py_INCREF(EXCEPT_NAME); + PyModule_AddObject(module, + STRINGIFY(EXCEPT_NAME), + EXCEPT_NAME); #if PY_MAJOR_VERSION >= 3 return module; #endif From 089565263bf1703fb490b3a2ca2adeefa7606764 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Sun, 12 Apr 2015 02:38:30 +0900 Subject: [PATCH 006/101] unparse func --- rapidxml-1.13/rapidxml_print.hpp | 67 +++++++++++++++++-------- setup.py | 2 +- rapidxml.cpp => src/rapidxml_module.cpp | 39 ++++++++++++-- 3 files changed, 83 insertions(+), 25 deletions(-) rename rapidxml.cpp => src/rapidxml_module.cpp (83%) diff --git a/rapidxml-1.13/rapidxml_print.hpp b/rapidxml-1.13/rapidxml_print.hpp index d03d5f5..b285353 100644 --- a/rapidxml-1.13/rapidxml_print.hpp +++ b/rapidxml-1.13/rapidxml_print.hpp @@ -28,10 +28,10 @@ namespace rapidxml //! \cond internal namespace internal { - + /////////////////////////////////////////////////////////////////////////// // Internal character operations - + // Copy characters from given range to given output iterator template inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out) @@ -40,7 +40,7 @@ namespace rapidxml *out++ = *begin++; return out; } - + // Copy characters from given range to given output iterator and expand // characters into references (< > ' " &) template @@ -59,17 +59,17 @@ namespace rapidxml case Ch('<'): *out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';'); break; - case Ch('>'): + case Ch('>'): *out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';'); break; - case Ch('\''): + case Ch('\''): *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';'); break; - case Ch('"'): + case Ch('"'): *out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';'); break; - case Ch('&'): - *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';'); + case Ch('&'): + *out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';'); break; default: *out++ = *begin; // No expansion, copy character @@ -101,7 +101,32 @@ namespace rapidxml /////////////////////////////////////////////////////////////////////////// // Internal printing operations - + template + inline OutIt print_children(OutIt out, const xml_node *node, int flags, int indent); + + template + inline OutIt print_attributes(OutIt out, const xml_node *node, int flags); + + template + inline OutIt print_data_node(OutIt out, const xml_node *node, int flags, int indent); + + template + inline OutIt print_cdata_node(OutIt out, const xml_node *node, int flags, int indent); + + template + inline OutIt print_element_node(OutIt out, const xml_node *node, int flags, int indent); + + template + inline OutIt print_declaration_node(OutIt out, const xml_node *node, int flags, int indent); + + template + inline OutIt print_comment_node(OutIt out, const xml_node *node, int flags, int indent); + + template + inline OutIt print_doctype_node(OutIt out, const xml_node *node, int flags, int indent); + + template + inline OutIt print_pi_node(OutIt out, const xml_node *node, int flags, int indent); // Print node template inline OutIt print_node(OutIt out, const xml_node *node, int flags, int indent) @@ -119,12 +144,12 @@ namespace rapidxml case node_element: out = print_element_node(out, node, flags, indent); break; - + // Data case node_data: out = print_data_node(out, node, flags, indent); break; - + // CDATA case node_cdata: out = print_cdata_node(out, node, flags, indent); @@ -139,7 +164,7 @@ namespace rapidxml case node_comment: out = print_comment_node(out, node, flags, indent); break; - + // Doctype case node_doctype: out = print_doctype_node(out, node, flags, indent); @@ -155,7 +180,7 @@ namespace rapidxml assert(0); break; } - + // If indenting not disabled, add line break after node if (!(flags & print_no_indenting)) *out = Ch('\n'), ++out; @@ -163,8 +188,8 @@ namespace rapidxml // Return modified iterator return out; } - - // Print children of the node + + // Print children of the node template inline OutIt print_children(OutIt out, const xml_node *node, int flags, int indent) { @@ -249,7 +274,7 @@ namespace rapidxml *out = Ch('<'), ++out; out = copy_chars(node->name(), node->name() + node->name_size(), out); out = print_attributes(out, node, flags); - + // If node is childless if (node->value_size() == 0 && !node->first_node()) { @@ -308,11 +333,11 @@ namespace rapidxml // Print attributes out = print_attributes(out, node, flags); - + // Print declaration end *out = Ch('?'), ++out; *out = Ch('>'), ++out; - + return out; } @@ -384,7 +409,7 @@ namespace rapidxml //! \param node Node to be printed. Pass xml_document to print entire document. //! \param flags Flags controlling how XML is printed. //! \return Output iterator pointing to position immediately after last character of printed text. - template + template inline OutIt print(OutIt out, const xml_node &node, int flags = 0) { return internal::print_node(out, &node, flags, 0); @@ -397,7 +422,7 @@ namespace rapidxml //! \param node Node to be printed. Pass xml_document to print entire document. //! \param flags Flags controlling how XML is printed. //! \return Output stream. - template + template inline std::basic_ostream &print(std::basic_ostream &out, const xml_node &node, int flags = 0) { print(std::ostream_iterator(out), node, flags); @@ -408,7 +433,7 @@ namespace rapidxml //! \param out Output stream to print to. //! \param node Node to be printed. //! \return Output stream. - template + template inline std::basic_ostream &operator <<(std::basic_ostream &out, const xml_node &node) { return print(out, node); diff --git a/setup.py b/setup.py index 12c5d01..7041ae3 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ define_macros=[('MAJOR_VERSION', '1'), ('MINOR_VERSION', '0')], include_dirs=['./rapidxml-1.13/'], - sources=["rapidxml.cpp"], + sources=["./src/rapidxml.cpp"], ) setup( diff --git a/rapidxml.cpp b/src/rapidxml_module.cpp similarity index 83% rename from rapidxml.cpp rename to src/rapidxml_module.cpp index 5ef1ac3..ed56cad 100644 --- a/rapidxml.cpp +++ b/src/rapidxml_module.cpp @@ -1,7 +1,7 @@ /* ** -*- coding: utf-8 -*- ** -** File: rapidxml.cpp +** File: rapidxml_module.cpp ** by Arzaroth Lekva ** arzaroth@arzaroth.com ** @@ -10,6 +10,9 @@ #include #include #include +#include +#include +#include #define STR(x) #x #define STRINGIFY(x) STR(x) @@ -37,6 +40,7 @@ static PyObject* EXCEPT_NAME; typedef struct { PyObject_HEAD rapidxml::xml_document<> doc; + char* text; } OBJ_OBJECT; static void CAT(OBJECT_NAME, _dealloc)(OBJ_OBJECT* self) { @@ -45,6 +49,7 @@ static void CAT(OBJECT_NAME, _dealloc)(OBJ_OBJECT* self) { #else self->ob_type->tp_free((PyObject*)self); #endif + free(self->text); } static PyObject* CAT(OBJECT_NAME, _new)(PyTypeObject* type, @@ -55,19 +60,27 @@ static PyObject* CAT(OBJECT_NAME, _new)(PyTypeObject* type, self = (OBJ_OBJECT*)type->tp_alloc(type, 0); return (PyObject*)self; } +#include static int CAT(OBJECT_NAME, _init)(OBJ_OBJECT* self, PyObject* args, PyObject* kwds) { - char* text; + const char* text; static char* kwlist[] = {"text", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &text)) { return -1; } + + self->text = strdup(text); + if (self->text == NULL) { + PyErr_SetString(EXCEPT_NAME, "Unable to allocate memory"); + return -1; + } + try { - self->doc.parse<0>(text); + self->doc.parse(self->text); } catch (rapidxml::parse_error &e) { PyErr_SetString(EXCEPT_NAME, e.what()); return -1; @@ -75,11 +88,31 @@ static int CAT(OBJECT_NAME, _init)(OBJ_OBJECT* self, return 0; } +static PyObject* CAT(OBJECT_NAME, _unparse)(OBJ_OBJECT* self, + PyObject* args, + PyObject* kwds) { + int pretty = 0; + PyObject* obj = NULL; + + static char* kwlist[] = {"pretty", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &obj)) { + pretty = 0; + } else if (obj) { + pretty = PyObject_IsTrue(obj); + } + std::string xml; + rapidxml::print(std::back_inserter(xml), self->doc, + !pretty ? rapidxml::print_no_indenting : 0); + return Py_BuildValue("s", xml.c_str()); +} + static PyMemberDef OBJ_MEMBERS[] = { {NULL} }; static PyMethodDef OBJ_METHS[] = { + {"unparse", (PyCFunction)CAT(OBJECT_NAME, _unparse), + METH_VARARGS | METH_KEYWORDS, "return xml string"}, {NULL} }; From c5a2a74f5022f74a13aa83d9b2b846d238441e9d Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Sun, 12 Apr 2015 04:37:33 +0900 Subject: [PATCH 007/101] split files --- inc/common.h | 33 ++++++++ setup.py | 7 +- src/rapidxml_module.cpp | 152 +------------------------------------ src/rapidxml_object.cpp | 164 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 204 insertions(+), 152 deletions(-) create mode 100644 inc/common.h create mode 100644 src/rapidxml_object.cpp diff --git a/inc/common.h b/inc/common.h new file mode 100644 index 0000000..0452cc0 --- /dev/null +++ b/inc/common.h @@ -0,0 +1,33 @@ +/* +** -*- coding: utf-8 -*- +** +** File: common.h +** by Arzaroth Lekva +** arzaroth@arzaroth.com +** +*/ + +#ifndef COMMON_H_ +# define COMMON_H_ + +# define STR(x) #x +# define STRINGIFY(x) STR(x) +# define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__) +# define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__ + +# define MODULE_DESC "rapidxml module for rapidxml bindings" +# define MODULE_NAME rapidxml +# define MODULE_METHS CAT(MODULE_NAME, _methods) + +# define OBJECT_NAME RapidXml +# define OBJ_TYPE CAT(MODULE_NAME, CAT(_, CAT(OBJECT_NAME, Type))) +# define OBJ_OBJECT CAT(MODULE_NAME, CAT(_, CAT(OBJECT_NAME, Object))) +# define OBJ_METHS CAT(OBJECT_NAME, _methods) +# define OBJ_MEMBERS CAT(OBJECT_NAME, _members) + +# define EXCEPT_NAME CAT(OBJECT_NAME, Error) + +extern PyTypeObject OBJ_TYPE; +extern PyObject* EXCEPT_NAME; + +#endif /* !COMMON_H_ */ diff --git a/setup.py b/setup.py index 7041ae3..62396cf 100644 --- a/setup.py +++ b/setup.py @@ -11,8 +11,11 @@ rapidxml = Extension("rapidxml", define_macros=[('MAJOR_VERSION', '1'), ('MINOR_VERSION', '0')], - include_dirs=['./rapidxml-1.13/'], - sources=["./src/rapidxml.cpp"], + include_dirs=['./rapidxml-1.13/', './inc/'], + sources=[ + "./src/rapidxml_module.cpp", + "./src/rapidxml_object.cpp", + ], ) setup( diff --git a/src/rapidxml_module.cpp b/src/rapidxml_module.cpp index ed56cad..753ed0e 100644 --- a/src/rapidxml_module.cpp +++ b/src/rapidxml_module.cpp @@ -9,158 +9,10 @@ #include #include -#include -#include -#include -#include -#define STR(x) #x -#define STRINGIFY(x) STR(x) -#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__) -#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__ +#include -struct module_state { - PyObject *error; -}; - -#define MODULE_DESC "rapidxml module for rapidxml bindings" -#define MODULE_NAME rapidxml -#define MODULE_METHS CAT(MODULE_NAME, _methods) - -#define OBJECT_NAME RapidXml -#define OBJ_TYPE CAT(MODULE_NAME, CAT(_, CAT(OBJECT_NAME, Type))) -#define OBJ_OBJECT CAT(MODULE_NAME, CAT(_, CAT(OBJECT_NAME, Object))) -#define OBJ_METHS CAT(OBJECT_NAME, _methods) -#define OBJ_MEMBERS CAT(OBJECT_NAME, _members) - -#define EXCEPT_NAME CAT(OBJECT_NAME, Error) - -static PyObject* EXCEPT_NAME; - -typedef struct { - PyObject_HEAD - rapidxml::xml_document<> doc; - char* text; -} OBJ_OBJECT; - -static void CAT(OBJECT_NAME, _dealloc)(OBJ_OBJECT* self) { - #if PY_MAJOR_VERSION >= 3 - Py_TYPE(self)->tp_free((PyObject*)self); - #else - self->ob_type->tp_free((PyObject*)self); - #endif - free(self->text); -} - -static PyObject* CAT(OBJECT_NAME, _new)(PyTypeObject* type, - PyObject* args, - PyObject* kwds) { - OBJ_OBJECT* self; - - self = (OBJ_OBJECT*)type->tp_alloc(type, 0); - return (PyObject*)self; -} -#include - -static int CAT(OBJECT_NAME, _init)(OBJ_OBJECT* self, - PyObject* args, - PyObject* kwds) { - const char* text; - - static char* kwlist[] = {"text", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, - &text)) { - return -1; - } - - self->text = strdup(text); - if (self->text == NULL) { - PyErr_SetString(EXCEPT_NAME, "Unable to allocate memory"); - return -1; - } - - try { - self->doc.parse(self->text); - } catch (rapidxml::parse_error &e) { - PyErr_SetString(EXCEPT_NAME, e.what()); - return -1; - } - return 0; -} - -static PyObject* CAT(OBJECT_NAME, _unparse)(OBJ_OBJECT* self, - PyObject* args, - PyObject* kwds) { - int pretty = 0; - PyObject* obj = NULL; - - static char* kwlist[] = {"pretty", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &obj)) { - pretty = 0; - } else if (obj) { - pretty = PyObject_IsTrue(obj); - } - std::string xml; - rapidxml::print(std::back_inserter(xml), self->doc, - !pretty ? rapidxml::print_no_indenting : 0); - return Py_BuildValue("s", xml.c_str()); -} - -static PyMemberDef OBJ_MEMBERS[] = { - {NULL} -}; - -static PyMethodDef OBJ_METHS[] = { - {"unparse", (PyCFunction)CAT(OBJECT_NAME, _unparse), - METH_VARARGS | METH_KEYWORDS, "return xml string"}, - {NULL} -}; - -static PyTypeObject OBJ_TYPE = { - #if PY_MAJOR_VERSION >= 3 - PyVarObject_HEAD_INIT(NULL, 0) - #else - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - #endif - STRINGIFY(MODULE_NAME) "." STRINGIFY(OBJECT_NAME), /* tp_name */ - sizeof(OBJ_OBJECT), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor)CAT(OBJECT_NAME, _dealloc), /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - "RapidXml objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - OBJ_METHS, /* tp_methods */ - OBJ_MEMBERS, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)CAT(OBJECT_NAME, _init), /* tp_init */ - 0, /* tp_alloc */ - CAT(OBJECT_NAME, _new), /* tp_new */ -}; +PyObject* EXCEPT_NAME; static PyMethodDef MODULE_METHS[] = { {NULL} diff --git a/src/rapidxml_object.cpp b/src/rapidxml_object.cpp new file mode 100644 index 0000000..b5340bb --- /dev/null +++ b/src/rapidxml_object.cpp @@ -0,0 +1,164 @@ +/* +** -*- coding: utf-8 -*- +** +** File: rapidxml.cpp +** by Arzaroth Lekva +** arzaroth@arzaroth.com +** +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +typedef struct { + PyObject_HEAD + rapidxml::xml_document<> doc; + std::vector text; +} OBJ_OBJECT; + +static void CAT(OBJECT_NAME, _dealloc)(OBJ_OBJECT* self) { + #if PY_MAJOR_VERSION >= 3 + Py_TYPE(self)->tp_free((PyObject*)self); + #else + self->ob_type->tp_free((PyObject*)self); + #endif +} + +static PyObject* CAT(OBJECT_NAME, _new)(PyTypeObject* type, + PyObject* args, + PyObject* kwds) { + OBJ_OBJECT* self; + + self = (OBJ_OBJECT*)type->tp_alloc(type, 0); + return (PyObject*)self; +} + +static int CAT(OBJECT_NAME, _init)(OBJ_OBJECT* self, + PyObject* args, + PyObject* kwds) { + const char* text; + int size; + int from_file = 0; + PyObject* from_file_obj = NULL; + + static char* kwlist[] = {"text", "from_file", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s#|O", kwlist, + &text, &size, &from_file_obj)) { + return -1; + } + if (from_file_obj) { + from_file = PyObject_IsTrue(from_file_obj); + } + + if (!from_file) { + self->text = std::vector(text, text + size); + } else { + std::ifstream f(text, std::ios::binary); + if (f.fail()) { + PyErr_SetString(EXCEPT_NAME, strerror(errno)); + return -1; + } + self->text = std::vector((std::istreambuf_iterator(f)), + std::istreambuf_iterator()); + } + self->text.push_back('\0'); + try { + self->doc.parse(&self->text[0]); + } catch (rapidxml::parse_error &e) { + PyErr_SetString(EXCEPT_NAME, e.what()); + return -1; + } + return 0; +} + +static PyObject* CAT(OBJECT_NAME, _unparse)(OBJ_OBJECT* self, + PyObject* args, + PyObject* kwds) { + int pretty = 0; + PyObject* pretty_obj = NULL; + + static char* kwlist[] = {"pretty", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &pretty_obj)) { + pretty = 0; + } else if (pretty_obj) { + pretty = PyObject_IsTrue(pretty_obj); + } + std::string xml; + rapidxml::print(std::back_inserter(xml), self->doc, + !pretty ? rapidxml::print_no_indenting : 0); + return Py_BuildValue("s", xml.c_str()); +} + +static PyObject* CAT(OBJECT_NAME, ___str__)(OBJ_OBJECT* self) { + return CAT(OBJECT_NAME, _unparse)(self, Py_BuildValue("(O)", Py_True), NULL); +} + +static PyObject* CAT(OBJECT_NAME, ___repr__)(OBJ_OBJECT* self) { + return CAT(OBJECT_NAME, _unparse)(self, Py_BuildValue("(O)", Py_False), NULL); +} + +static PyMemberDef OBJ_MEMBERS[] = { + {NULL} +}; + +static PyMethodDef OBJ_METHS[] = { + {"unparse", (PyCFunction)CAT(OBJECT_NAME, _unparse), + METH_VARARGS | METH_KEYWORDS, "return xml string"}, + {NULL} +}; + +PyTypeObject OBJ_TYPE = { + #if PY_MAJOR_VERSION >= 3 + PyVarObject_HEAD_INIT(NULL, 0) + #else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + #endif + STRINGIFY(MODULE_NAME) "." STRINGIFY(OBJECT_NAME), /* tp_name */ + sizeof(OBJ_OBJECT), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)CAT(OBJECT_NAME, _dealloc), /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + (reprfunc)CAT(OBJECT_NAME, ___repr__), /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)CAT(OBJECT_NAME, ___str__), /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "RapidXml objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + OBJ_METHS, /* tp_methods */ + OBJ_MEMBERS, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)CAT(OBJECT_NAME, _init), /* tp_init */ + 0, /* tp_alloc */ + CAT(OBJECT_NAME, _new), /* tp_new */ +}; From 3e1cb54c9027fe67cb9d1bbc524615749b213a2a Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Tue, 14 Apr 2015 09:37:05 +0900 Subject: [PATCH 008/101] base object, get rid of useless macro --- inc/common.h | 34 ++++---- setup.py | 1 + src/base_object.cpp | 179 ++++++++++++++++++++++++++++++++++++++++ src/rapidxml_module.cpp | 48 ++++++----- src/rapidxml_object.cpp | 127 +++++++++++++++++----------- 5 files changed, 303 insertions(+), 86 deletions(-) create mode 100644 src/base_object.cpp diff --git a/inc/common.h b/inc/common.h index 0452cc0..20e20f1 100644 --- a/inc/common.h +++ b/inc/common.h @@ -7,27 +7,25 @@ ** */ -#ifndef COMMON_H_ -# define COMMON_H_ +#ifndef COMMON_H_ +# define COMMON_H_ -# define STR(x) #x -# define STRINGIFY(x) STR(x) -# define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__) -# define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__ +# include +# include -# define MODULE_DESC "rapidxml module for rapidxml bindings" -# define MODULE_NAME rapidxml -# define MODULE_METHS CAT(MODULE_NAME, _methods) +typedef struct { + PyObject_HEAD + rapidxml::xml_base<>* underlying_obj; +} rapidxml_BaseObject; -# define OBJECT_NAME RapidXml -# define OBJ_TYPE CAT(MODULE_NAME, CAT(_, CAT(OBJECT_NAME, Type))) -# define OBJ_OBJECT CAT(MODULE_NAME, CAT(_, CAT(OBJECT_NAME, Object))) -# define OBJ_METHS CAT(OBJECT_NAME, _methods) -# define OBJ_MEMBERS CAT(OBJECT_NAME, _members) +typedef struct { + rapidxml_BaseObject base; + std::vector text; +} rapidxml_RapidXmlObject; -# define EXCEPT_NAME CAT(OBJECT_NAME, Error) +extern PyTypeObject rapidxml_BaseType; +extern PyTypeObject rapidxml_RapidXmlType; -extern PyTypeObject OBJ_TYPE; -extern PyObject* EXCEPT_NAME; +extern PyObject* RapidXmlError; -#endif /* !COMMON_H_ */ +#endif /* !COMMON_H_ */ diff --git a/setup.py b/setup.py index 62396cf..35c755e 100644 --- a/setup.py +++ b/setup.py @@ -14,6 +14,7 @@ include_dirs=['./rapidxml-1.13/', './inc/'], sources=[ "./src/rapidxml_module.cpp", + "./src/base_object.cpp", "./src/rapidxml_object.cpp", ], ) diff --git a/src/base_object.cpp b/src/base_object.cpp new file mode 100644 index 0000000..930a35a --- /dev/null +++ b/src/base_object.cpp @@ -0,0 +1,179 @@ +/* +** -*- coding: utf-8 -*- +** +** File: base_object.cpp +** by Arzaroth Lekva +** arzaroth@arzaroth.com +** +*/ + +#include +#include +#include + +#include + +static void rapidxml_BaseObject_dealloc(rapidxml_BaseObject* self) { +#if PY_MAJOR_VERSION >= 3 + Py_TYPE(self)->tp_free((PyObject*)self); +#else + self->ob_type->tp_free((PyObject*)self); +#endif +} + +static PyObject* rapidxml_BaseObject_new(PyTypeObject* type, + PyObject* args, + PyObject* kwds) { + rapidxml_BaseObject* self; + + self = (rapidxml_BaseObject*)type->tp_alloc(type, 0); + if (self != NULL) { + self->underlying_obj = NULL; + } + return (PyObject*)self; +} + +static int rapidxml_BaseObject_init(rapidxml_BaseObject* self, + PyObject* args, + PyObject* kwds) { + return 0; +} + +static PyObject* rapidxml_BaseObject_getname(rapidxml_BaseObject* self, + void* closure) { + if (self->underlying_obj == NULL) { + return Py_BuildValue("s", ""); + } + return Py_BuildValue("s", self->underlying_obj->name()); +} + +static int rapidxml_BaseObject_setname(rapidxml_BaseObject* self, + PyObject* arg, + void* closure) { + const char* name; + + if (self->underlying_obj == NULL || arg == NULL) { + return -1; + } + if (! +#if PY_MAJOR_VERSION >= 3 + PyUnicode_Check(arg) +#else + PyString_Check(arg) +#endif + ) { + PyErr_SetString(PyExc_TypeError, + "name attribute must be a string"); + return -1; + } + if (!PyArg_Parse(arg, "s", &name)) { + return -1; + } + self->underlying_obj->name(name); + return 0; +} + +static PyObject* rapidxml_BaseObject_getvalue(rapidxml_BaseObject* self, + void* closure) { + if (self->underlying_obj == NULL) { + return Py_BuildValue("s", ""); + } + return Py_BuildValue("s", self->underlying_obj->value()); +} + +static int rapidxml_BaseObject_setvalue(rapidxml_BaseObject* self, + PyObject* arg, + void* closure) { + const char* value; + + if (self->underlying_obj == NULL || arg == NULL) { + return -1; + } + if (! +#if PY_MAJOR_VERSION >= 3 + PyUnicode_Check(arg) +#else + PyString_Check(arg) +#endif + ) { + PyErr_SetString(PyExc_TypeError, + "value attribute must be a string"); + return -1; + } + if (!PyArg_Parse(arg, "s", &value)) { + return -1; + } + self->underlying_obj->value(value); + return 0; +} + +static PyGetSetDef rapidxml_BaseObject_getseters[] = { + {"name", + (getter)rapidxml_BaseObject_getname, (setter)rapidxml_BaseObject_setname, + "name of xml entity"}, + {"value", + (getter)rapidxml_BaseObject_getvalue, (setter)rapidxml_BaseObject_setvalue, + "value of xml entity"}, + {NULL} +}; + +static PyMemberDef rapidxml_BaseObject_members[] = { + {NULL} +}; + +static PyMethodDef rapidxml_BaseObject_methods[] = { + {NULL} +}; + +PyTypeObject rapidxml_BaseType = { + #if PY_MAJOR_VERSION >= 3 + PyVarObject_HEAD_INIT(NULL, 0) + #else + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + #endif + "rapidxml.Base", /* tp_name */ + sizeof(rapidxml_BaseObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)rapidxml_BaseObject_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "rapidxml base object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + rapidxml_BaseObject_methods, /* tp_methods */ + rapidxml_BaseObject_members, /* tp_members */ + rapidxml_BaseObject_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)rapidxml_BaseObject_init, /* tp_init */ + 0, /* tp_alloc */ + (newfunc)rapidxml_BaseObject_new, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +}; diff --git a/src/rapidxml_module.cpp b/src/rapidxml_module.cpp index 753ed0e..f6bcfa6 100644 --- a/src/rapidxml_module.cpp +++ b/src/rapidxml_module.cpp @@ -12,9 +12,9 @@ #include -PyObject* EXCEPT_NAME; +PyObject* RapidXmlError; -static PyMethodDef MODULE_METHS[] = { +static PyMethodDef module_methods[] = { {NULL} }; @@ -22,10 +22,10 @@ static PyMethodDef MODULE_METHS[] = { static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, - STRINGIFY(MODULE_NAME), - MODULE_DESC, + "rapidxml", + "python module for rapidxml bindings", -1, - MODULE_METHS, + module_methods, NULL, NULL, NULL, @@ -34,41 +34,49 @@ static struct PyModuleDef moduledef = { # define INITERROR return NULL -PyMODINIT_FUNC CAT(PyInit_, MODULE_NAME)(void) +PyMODINIT_FUNC PyInit_rapidxml(void) #else # define INITERROR return -PyMODINIT_FUNC CAT(init, MODULE_NAME)(void) +PyMODINIT_FUNC initrapidxml(void) #endif { PyObject* module; - OBJ_TYPE.tp_new = PyType_GenericNew; - if (PyType_Ready(&OBJ_TYPE) < 0) + if (PyType_Ready(&rapidxml_BaseType) < 0) + INITERROR; + rapidxml_RapidXmlType.tp_base = &rapidxml_BaseType; + if (PyType_Ready(&rapidxml_RapidXmlType) < 0) INITERROR; #if PY_MAJOR_VERSION >= 3 module = PyModule_Create(&moduledef); #else - module = Py_InitModule3(STRINGIFY(MODULE_NAME), - MODULE_METHS, - MODULE_DESC); + module = Py_InitModule3("rapidxml", + module_methods, + "rapidxml module for rapidxml bindings"); #endif if (module == NULL) INITERROR; - Py_INCREF(&OBJ_TYPE); + Py_INCREF(&rapidxml_BaseType); + PyModule_AddObject(module, + "Base", + (PyObject *)&rapidxml_BaseType); + Py_INCREF(&rapidxml_RapidXmlType); + PyModule_AddObject(module, - STRINGIFY(OBJECT_NAME), - (PyObject *)&OBJ_TYPE); + "RapidXml", + (PyObject *)&rapidxml_RapidXmlType); - EXCEPT_NAME = PyErr_NewException(STRINGIFY(MODULE_NAME) "." STRINGIFY(EXCEPT_NAME), - NULL, NULL); - Py_INCREF(EXCEPT_NAME); + RapidXmlError = PyErr_NewException("rapidxml.RapidXmlError", + NULL, NULL); + Py_INCREF(RapidXmlError); PyModule_AddObject(module, - STRINGIFY(EXCEPT_NAME), - EXCEPT_NAME); + "RapidXmlError", + RapidXmlError); + #if PY_MAJOR_VERSION >= 3 return module; #endif diff --git a/src/rapidxml_object.cpp b/src/rapidxml_object.cpp index b5340bb..24cef56 100644 --- a/src/rapidxml_object.cpp +++ b/src/rapidxml_object.cpp @@ -1,7 +1,7 @@ /* ** -*- coding: utf-8 -*- ** -** File: rapidxml.cpp +** File: rapidxml_object.cpp ** by Arzaroth Lekva ** arzaroth@arzaroth.com ** @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -20,37 +19,26 @@ #include -typedef struct { - PyObject_HEAD - rapidxml::xml_document<> doc; - std::vector text; -} OBJ_OBJECT; - -static void CAT(OBJECT_NAME, _dealloc)(OBJ_OBJECT* self) { - #if PY_MAJOR_VERSION >= 3 +static void rapidxml_RapidXmlObject_dealloc(rapidxml_BaseObject* self) { + free(self->underlying_obj); +#if PY_MAJOR_VERSION >= 3 Py_TYPE(self)->tp_free((PyObject*)self); - #else +#else self->ob_type->tp_free((PyObject*)self); - #endif +#endif } -static PyObject* CAT(OBJECT_NAME, _new)(PyTypeObject* type, +static int rapidxml_RapidXmlObject_init(rapidxml_RapidXmlObject* self, PyObject* args, PyObject* kwds) { - OBJ_OBJECT* self; - - self = (OBJ_OBJECT*)type->tp_alloc(type, 0); - return (PyObject*)self; -} - -static int CAT(OBJECT_NAME, _init)(OBJ_OBJECT* self, - PyObject* args, - PyObject* kwds) { const char* text; int size; int from_file = 0; PyObject* from_file_obj = NULL; + if (rapidxml_BaseType.tp_init((PyObject*)self, args, kwds) < 0) { + return -1; + } static char* kwlist[] = {"text", "from_file", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "s#|O", kwlist, &text, &size, &from_file_obj)) { @@ -65,7 +53,7 @@ static int CAT(OBJECT_NAME, _init)(OBJ_OBJECT* self, } else { std::ifstream f(text, std::ios::binary); if (f.fail()) { - PyErr_SetString(EXCEPT_NAME, strerror(errno)); + PyErr_SetString(RapidXmlError, strerror(errno)); return -1; } self->text = std::vector((std::istreambuf_iterator(f)), @@ -73,17 +61,38 @@ static int CAT(OBJECT_NAME, _init)(OBJ_OBJECT* self, } self->text.push_back('\0'); try { - self->doc.parse(&self->text[0]); + self->base.underlying_obj = new rapidxml::xml_document<>(); + ((rapidxml::xml_document<>*)self->base.underlying_obj)->parse(&self->text[0]); } catch (rapidxml::parse_error &e) { - PyErr_SetString(EXCEPT_NAME, e.what()); + PyErr_SetString(RapidXmlError, e.what()); return -1; } return 0; } -static PyObject* CAT(OBJECT_NAME, _unparse)(OBJ_OBJECT* self, - PyObject* args, - PyObject* kwds) { +static PyObject* rapidxml_RapidXmlObject_first_node(rapidxml_RapidXmlObject* self, + PyObject* args, + PyObject* kwds) { + const char* name = NULL; + + static char* kwlist[] = {"name", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist, + &name)) { + Py_INCREF(Py_None); + return Py_None; + } + rapidxml::xml_node<>* node = ((rapidxml::xml_document<>*)self->base.underlying_obj)->first_node(name); + if (!node) { + Py_INCREF(Py_None); + return Py_None; + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* rapidxml_RapidXmlObject_unparse(rapidxml_RapidXmlObject* self, + PyObject* args, + PyObject* kwds) { int pretty = 0; PyObject* pretty_obj = NULL; @@ -94,71 +103,93 @@ static PyObject* CAT(OBJECT_NAME, _unparse)(OBJ_OBJECT* self, pretty = PyObject_IsTrue(pretty_obj); } std::string xml; - rapidxml::print(std::back_inserter(xml), self->doc, + rapidxml::print(std::back_inserter(xml), + *((rapidxml::xml_document<>*)self->base.underlying_obj), !pretty ? rapidxml::print_no_indenting : 0); return Py_BuildValue("s", xml.c_str()); } -static PyObject* CAT(OBJECT_NAME, ___str__)(OBJ_OBJECT* self) { - return CAT(OBJECT_NAME, _unparse)(self, Py_BuildValue("(O)", Py_True), NULL); +static PyObject* rapidxml_RapidXmlObject___str__(rapidxml_RapidXmlObject* self) { + PyObject* args; + PyObject* res; + + args = Py_BuildValue("(O)", Py_True); + res = rapidxml_RapidXmlObject_unparse(self, args, NULL); + Py_DECREF(args); + return res; } -static PyObject* CAT(OBJECT_NAME, ___repr__)(OBJ_OBJECT* self) { - return CAT(OBJECT_NAME, _unparse)(self, Py_BuildValue("(O)", Py_False), NULL); +static PyObject* rapidxml_RapidXmlObject___repr__(rapidxml_RapidXmlObject* self) { + PyObject* args; + PyObject* res; + + args = Py_BuildValue("(O)", Py_False); + res = rapidxml_RapidXmlObject_unparse(self, args, NULL); + Py_DECREF(args); + return res; } -static PyMemberDef OBJ_MEMBERS[] = { +static PyMemberDef rapidxml_RapidXmlObject_members[] = { {NULL} }; -static PyMethodDef OBJ_METHS[] = { - {"unparse", (PyCFunction)CAT(OBJECT_NAME, _unparse), +static PyMethodDef rapidxml_RapidXmlObject_methods[] = { + {"unparse", (PyCFunction)rapidxml_RapidXmlObject_unparse, METH_VARARGS | METH_KEYWORDS, "return xml string"}, + {"first_node", (PyCFunction)rapidxml_RapidXmlObject_first_node, + METH_VARARGS | METH_KEYWORDS, "gets first child node, optionally matching node name"}, {NULL} }; -PyTypeObject OBJ_TYPE = { +PyTypeObject rapidxml_RapidXmlType = { #if PY_MAJOR_VERSION >= 3 PyVarObject_HEAD_INIT(NULL, 0) #else PyObject_HEAD_INIT(NULL) 0, /* ob_size */ #endif - STRINGIFY(MODULE_NAME) "." STRINGIFY(OBJECT_NAME), /* tp_name */ - sizeof(OBJ_OBJECT), /* tp_basicsize */ + "rapidxml.RapidXml", /* tp_name */ + sizeof(rapidxml_RapidXmlObject), /* tp_basicsize */ 0, /* tp_itemsize */ - (destructor)CAT(OBJECT_NAME, _dealloc), /* tp_dealloc */ + (destructor)rapidxml_RapidXmlObject_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ - (reprfunc)CAT(OBJECT_NAME, ___repr__), /* tp_repr */ + (reprfunc)rapidxml_RapidXmlObject___repr__, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ - (reprfunc)CAT(OBJECT_NAME, ___str__), /* tp_str */ + (reprfunc)rapidxml_RapidXmlObject___str__, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - "RapidXml objects", /* tp_doc */ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "class representing a rapidxml::xml_document", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ - OBJ_METHS, /* tp_methods */ - OBJ_MEMBERS, /* tp_members */ + rapidxml_RapidXmlObject_methods, /* tp_methods */ + rapidxml_RapidXmlObject_members, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - (initproc)CAT(OBJECT_NAME, _init), /* tp_init */ + (initproc)rapidxml_RapidXmlObject_init, /* tp_init */ 0, /* tp_alloc */ - CAT(OBJECT_NAME, _new), /* tp_new */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ }; From 5f838d60bc66e3044e3e6d1145f93e086add0355 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Tue, 14 Apr 2015 10:37:49 +0900 Subject: [PATCH 009/101] node object, memory_pool for each object --- inc/common.h | 8 ++- setup.py | 1 + src/base_object.cpp | 17 ++--- src/node_object.cpp | 146 ++++++++++++++++++++++++++++++++++++++++ src/rapidxml_module.cpp | 12 +++- src/rapidxml_object.cpp | 109 +++++------------------------- 6 files changed, 185 insertions(+), 108 deletions(-) create mode 100644 src/node_object.cpp diff --git a/inc/common.h b/inc/common.h index 20e20f1..3a92089 100644 --- a/inc/common.h +++ b/inc/common.h @@ -11,19 +11,23 @@ # define COMMON_H_ # include -# include typedef struct { PyObject_HEAD rapidxml::xml_base<>* underlying_obj; + rapidxml::memory_pool<> memory_pool; } rapidxml_BaseObject; typedef struct { rapidxml_BaseObject base; - std::vector text; +} rapidxml_NodeObject; + +typedef struct { + rapidxml_NodeObject base; } rapidxml_RapidXmlObject; extern PyTypeObject rapidxml_BaseType; +extern PyTypeObject rapidxml_NodeType; extern PyTypeObject rapidxml_RapidXmlType; extern PyObject* RapidXmlError; diff --git a/setup.py b/setup.py index 35c755e..90b5c0f 100644 --- a/setup.py +++ b/setup.py @@ -15,6 +15,7 @@ sources=[ "./src/rapidxml_module.cpp", "./src/base_object.cpp", + "./src/node_object.cpp", "./src/rapidxml_object.cpp", ], ) diff --git a/src/base_object.cpp b/src/base_object.cpp index 930a35a..b79e542 100644 --- a/src/base_object.cpp +++ b/src/base_object.cpp @@ -14,11 +14,7 @@ #include static void rapidxml_BaseObject_dealloc(rapidxml_BaseObject* self) { -#if PY_MAJOR_VERSION >= 3 Py_TYPE(self)->tp_free((PyObject*)self); -#else - self->ob_type->tp_free((PyObject*)self); -#endif } static PyObject* rapidxml_BaseObject_new(PyTypeObject* type, @@ -69,7 +65,7 @@ static int rapidxml_BaseObject_setname(rapidxml_BaseObject* self, if (!PyArg_Parse(arg, "s", &name)) { return -1; } - self->underlying_obj->name(name); + self->underlying_obj->name(self->memory_pool.allocate_string(name)); return 0; } @@ -103,7 +99,7 @@ static int rapidxml_BaseObject_setvalue(rapidxml_BaseObject* self, if (!PyArg_Parse(arg, "s", &value)) { return -1; } - self->underlying_obj->value(value); + self->underlying_obj->value(self->memory_pool.allocate_string(value)); return 0; } @@ -126,12 +122,7 @@ static PyMethodDef rapidxml_BaseObject_methods[] = { }; PyTypeObject rapidxml_BaseType = { - #if PY_MAJOR_VERSION >= 3 PyVarObject_HEAD_INIT(NULL, 0) - #else - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - #endif "rapidxml.Base", /* tp_name */ sizeof(rapidxml_BaseObject), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -150,8 +141,8 @@ PyTypeObject rapidxml_BaseType = { 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - "rapidxml base object", /* tp_doc */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "class representing a rapidxml::xml_base", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ diff --git a/src/node_object.cpp b/src/node_object.cpp new file mode 100644 index 0000000..e3a687a --- /dev/null +++ b/src/node_object.cpp @@ -0,0 +1,146 @@ +/* +** -*- coding: utf-8 -*- +** +** File: node_object.cpp +** by Arzaroth Lekva +** arzaroth@arzaroth.com +** +*/ + +#include +#include +#include +#include +#include + +#include + +static int rapidxml_NodeObject_init(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + return 0; +} + +static PyObject* rapidxml_NodeObject_first_node(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + const char* name = NULL; + rapidxml_NodeObject* new_node; + char kw_name[] = "name"; + + static char* kwlist[] = {kw_name, NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist, + &name)) { + Py_INCREF(Py_None); + return Py_None; + } + rapidxml::xml_node<>* node = ((rapidxml::xml_node<>*)self->base.underlying_obj)->first_node(name); + if (!node) { + Py_INCREF(Py_None); + return Py_None; + } + new_node = (rapidxml_NodeObject*)PyObject_CallObject((PyObject*)&rapidxml_NodeType, + NULL); + new_node->base.underlying_obj = node; + return (PyObject*)new_node; +} + +static PyObject* rapidxml_NodeObject_unparse(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + int pretty = 0; + PyObject* pretty_obj = NULL; + std::string xml; + char kw_pretty[] = "pretty"; + + static char* kwlist[] = {kw_pretty, NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &pretty_obj)) { + pretty = 0; + } else if (pretty_obj) { + pretty = PyObject_IsTrue(pretty_obj); + } + rapidxml::print(std::back_inserter(xml), + *((rapidxml::xml_document<>*)self->base.underlying_obj), + !pretty ? rapidxml::print_no_indenting : 0); + return Py_BuildValue("s", xml.c_str()); +} + +static PyObject* rapidxml_NodeObject___str__(rapidxml_NodeObject* self) { + PyObject* args; + PyObject* res; + + args = Py_BuildValue("(O)", Py_True); + res = rapidxml_NodeObject_unparse(self, args, NULL); + Py_DECREF(args); + return res; +} + +static PyObject* rapidxml_NodeObject___repr__(rapidxml_NodeObject* self) { + PyObject* args; + PyObject* res; + + args = Py_BuildValue("(O)", Py_False); + res = rapidxml_NodeObject_unparse(self, args, NULL); + Py_DECREF(args); + return res; +} + +static PyMemberDef rapidxml_NodeObject_members[] = { + {NULL} +}; + +static PyMethodDef rapidxml_NodeObject_methods[] = { + {"first_node", (PyCFunction)rapidxml_NodeObject_first_node, + METH_VARARGS | METH_KEYWORDS, "gets first child node, optionally matching node name"}, + {"unparse", (PyCFunction)rapidxml_NodeObject_unparse, + METH_VARARGS | METH_KEYWORDS, "return xml string"}, + {NULL} +}; + +PyTypeObject rapidxml_NodeType = { + PyVarObject_HEAD_INIT(NULL, 0) + "rapidxml.Node", /* tp_name */ + sizeof(rapidxml_NodeObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + (reprfunc)rapidxml_NodeObject___repr__, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)rapidxml_NodeObject___str__, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "class representing a rapidxml::xml_node", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + rapidxml_NodeObject_methods, /* tp_methods */ + rapidxml_NodeObject_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)rapidxml_NodeObject_init, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +}; diff --git a/src/rapidxml_module.cpp b/src/rapidxml_module.cpp index f6bcfa6..371f2bc 100644 --- a/src/rapidxml_module.cpp +++ b/src/rapidxml_module.cpp @@ -46,7 +46,10 @@ PyMODINIT_FUNC initrapidxml(void) if (PyType_Ready(&rapidxml_BaseType) < 0) INITERROR; - rapidxml_RapidXmlType.tp_base = &rapidxml_BaseType; + rapidxml_NodeType.tp_base = &rapidxml_BaseType; + if (PyType_Ready(&rapidxml_NodeType) < 0) + INITERROR; + rapidxml_RapidXmlType.tp_base = &rapidxml_NodeType; if (PyType_Ready(&rapidxml_RapidXmlType) < 0) INITERROR; @@ -64,8 +67,13 @@ PyMODINIT_FUNC initrapidxml(void) PyModule_AddObject(module, "Base", (PyObject *)&rapidxml_BaseType); - Py_INCREF(&rapidxml_RapidXmlType); + Py_INCREF(&rapidxml_NodeType); + PyModule_AddObject(module, + "Node", + (PyObject *)&rapidxml_NodeType); + + Py_INCREF(&rapidxml_RapidXmlType); PyModule_AddObject(module, "RapidXml", (PyObject *)&rapidxml_RapidXmlType); diff --git a/src/rapidxml_object.cpp b/src/rapidxml_object.cpp index 24cef56..a58e1da 100644 --- a/src/rapidxml_object.cpp +++ b/src/rapidxml_object.cpp @@ -10,8 +10,7 @@ #include #include #include -#include -#include +#include #include #include #include @@ -19,50 +18,46 @@ #include -static void rapidxml_RapidXmlObject_dealloc(rapidxml_BaseObject* self) { - free(self->underlying_obj); -#if PY_MAJOR_VERSION >= 3 +static void rapidxml_RapidXmlObject_dealloc(rapidxml_RapidXmlObject* self) { + free(self->base.base.underlying_obj); Py_TYPE(self)->tp_free((PyObject*)self); -#else - self->ob_type->tp_free((PyObject*)self); -#endif } static int rapidxml_RapidXmlObject_init(rapidxml_RapidXmlObject* self, PyObject* args, PyObject* kwds) { const char* text; - int size; int from_file = 0; PyObject* from_file_obj = NULL; + char kw_text[] = "text"; + char kw_from_file[] = "from_file"; + std::vector text_vector; - if (rapidxml_BaseType.tp_init((PyObject*)self, args, kwds) < 0) { + if (rapidxml_NodeType.tp_init((PyObject*)self, args, kwds) < 0) { return -1; } - static char* kwlist[] = {"text", "from_file", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s#|O", kwlist, - &text, &size, &from_file_obj)) { + static char* kwlist[] = {kw_text, kw_from_file, NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|O", kwlist, + &text, &from_file_obj)) { return -1; } if (from_file_obj) { from_file = PyObject_IsTrue(from_file_obj); } - if (!from_file) { - self->text = std::vector(text, text + size); - } else { + if (from_file) { std::ifstream f(text, std::ios::binary); if (f.fail()) { PyErr_SetString(RapidXmlError, strerror(errno)); return -1; } - self->text = std::vector((std::istreambuf_iterator(f)), - std::istreambuf_iterator()); + text_vector = std::vector((std::istreambuf_iterator(f)), + std::istreambuf_iterator()); + text = &text_vector[0]; } - self->text.push_back('\0'); try { - self->base.underlying_obj = new rapidxml::xml_document<>(); - ((rapidxml::xml_document<>*)self->base.underlying_obj)->parse(&self->text[0]); + self->base.base.underlying_obj = new rapidxml::xml_document<>(); + ((rapidxml::xml_document<>*)self->base.base.underlying_obj)->parse(self->base.base.memory_pool.allocate_string(text)); } catch (rapidxml::parse_error &e) { PyErr_SetString(RapidXmlError, e.what()); return -1; @@ -70,84 +65,16 @@ static int rapidxml_RapidXmlObject_init(rapidxml_RapidXmlObject* self, return 0; } -static PyObject* rapidxml_RapidXmlObject_first_node(rapidxml_RapidXmlObject* self, - PyObject* args, - PyObject* kwds) { - const char* name = NULL; - - static char* kwlist[] = {"name", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist, - &name)) { - Py_INCREF(Py_None); - return Py_None; - } - rapidxml::xml_node<>* node = ((rapidxml::xml_document<>*)self->base.underlying_obj)->first_node(name); - if (!node) { - Py_INCREF(Py_None); - return Py_None; - } - Py_INCREF(Py_None); - return Py_None; -} - -static PyObject* rapidxml_RapidXmlObject_unparse(rapidxml_RapidXmlObject* self, - PyObject* args, - PyObject* kwds) { - int pretty = 0; - PyObject* pretty_obj = NULL; - - static char* kwlist[] = {"pretty", NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &pretty_obj)) { - pretty = 0; - } else if (pretty_obj) { - pretty = PyObject_IsTrue(pretty_obj); - } - std::string xml; - rapidxml::print(std::back_inserter(xml), - *((rapidxml::xml_document<>*)self->base.underlying_obj), - !pretty ? rapidxml::print_no_indenting : 0); - return Py_BuildValue("s", xml.c_str()); -} - -static PyObject* rapidxml_RapidXmlObject___str__(rapidxml_RapidXmlObject* self) { - PyObject* args; - PyObject* res; - - args = Py_BuildValue("(O)", Py_True); - res = rapidxml_RapidXmlObject_unparse(self, args, NULL); - Py_DECREF(args); - return res; -} - -static PyObject* rapidxml_RapidXmlObject___repr__(rapidxml_RapidXmlObject* self) { - PyObject* args; - PyObject* res; - - args = Py_BuildValue("(O)", Py_False); - res = rapidxml_RapidXmlObject_unparse(self, args, NULL); - Py_DECREF(args); - return res; -} - static PyMemberDef rapidxml_RapidXmlObject_members[] = { {NULL} }; static PyMethodDef rapidxml_RapidXmlObject_methods[] = { - {"unparse", (PyCFunction)rapidxml_RapidXmlObject_unparse, - METH_VARARGS | METH_KEYWORDS, "return xml string"}, - {"first_node", (PyCFunction)rapidxml_RapidXmlObject_first_node, - METH_VARARGS | METH_KEYWORDS, "gets first child node, optionally matching node name"}, {NULL} }; PyTypeObject rapidxml_RapidXmlType = { - #if PY_MAJOR_VERSION >= 3 PyVarObject_HEAD_INIT(NULL, 0) - #else - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - #endif "rapidxml.RapidXml", /* tp_name */ sizeof(rapidxml_RapidXmlObject), /* tp_basicsize */ 0, /* tp_itemsize */ @@ -156,13 +83,13 @@ PyTypeObject rapidxml_RapidXmlType = { 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ - (reprfunc)rapidxml_RapidXmlObject___repr__, /* tp_repr */ + 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ - (reprfunc)rapidxml_RapidXmlObject___str__, /* tp_str */ + 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ From 7803e3d559f8f97b5b228631557bcc0adda54f20 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Tue, 14 Apr 2015 11:01:43 +0900 Subject: [PATCH 010/101] readme --- README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..2126ec3 --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +python_rapidxml +=============== + +A library providing python bindings for rapidxml + +Example +--------------- + + import rapidxml + + r = rapidxml.RapidXml("foo") # parsing from string + test = r.first_node("test") # get first node named test + test.name = "foo" # changing node's name to foo + r.first_node("test2").value = "bar" # changing node's value to bar + + print(str(r)) # will output prettified string of the xml document + print(test) # also works for nodes + + with open('dump.xml', 'w') as f: + f.write(str(r)) + r = rapidxml.RapidXml("dump.xml", True) # loading from file + + assert(str(r) == r.unparse(True)) # is always True + assert(repr(r) == r.unparse()) # also always True, returns flat version + + +Project Current State +=============== + +This project is currently under *heavy* development. From f237e191883cc3db3bf880b600c92e031772836d Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Tue, 14 Apr 2015 11:50:30 +0900 Subject: [PATCH 011/101] using document memory pool --- inc/common.h | 4 ++-- src/base_object.cpp | 23 +++++++++++++++++++---- src/node_object.cpp | 3 ++- src/rapidxml_module.cpp | 10 +++++----- src/rapidxml_object.cpp | 10 +++++++--- test/simple.py | 31 +++++++++++++++++++++++++++++++ 6 files changed, 66 insertions(+), 15 deletions(-) create mode 100755 test/simple.py diff --git a/inc/common.h b/inc/common.h index 3a92089..dd37eb9 100644 --- a/inc/common.h +++ b/inc/common.h @@ -15,7 +15,7 @@ typedef struct { PyObject_HEAD rapidxml::xml_base<>* underlying_obj; - rapidxml::memory_pool<> memory_pool; + rapidxml::xml_document<>* document; } rapidxml_BaseObject; typedef struct { @@ -30,6 +30,6 @@ extern PyTypeObject rapidxml_BaseType; extern PyTypeObject rapidxml_NodeType; extern PyTypeObject rapidxml_RapidXmlType; -extern PyObject* RapidXmlError; +extern PyObject* rapidxml_RapidXmlError; #endif /* !COMMON_H_ */ diff --git a/src/base_object.cpp b/src/base_object.cpp index b79e542..0c4f822 100644 --- a/src/base_object.cpp +++ b/src/base_object.cpp @@ -25,6 +25,7 @@ static PyObject* rapidxml_BaseObject_new(PyTypeObject* type, self = (rapidxml_BaseObject*)type->tp_alloc(type, 0); if (self != NULL) { self->underlying_obj = NULL; + self->document = NULL; } return (PyObject*)self; } @@ -48,7 +49,14 @@ static int rapidxml_BaseObject_setname(rapidxml_BaseObject* self, void* closure) { const char* name; - if (self->underlying_obj == NULL || arg == NULL) { + if (self->underlying_obj == NULL || self->document == NULL) { + PyErr_SetString(rapidxml_RapidXmlError, + "underlying mechanism failed"); + return -1; + } + if (arg == NULL) { + PyErr_SetString(PyExc_TypeError, + "name attribute must not be null"); return -1; } if (! @@ -65,7 +73,7 @@ static int rapidxml_BaseObject_setname(rapidxml_BaseObject* self, if (!PyArg_Parse(arg, "s", &name)) { return -1; } - self->underlying_obj->name(self->memory_pool.allocate_string(name)); + self->underlying_obj->name(self->document->allocate_string(name)); return 0; } @@ -82,7 +90,14 @@ static int rapidxml_BaseObject_setvalue(rapidxml_BaseObject* self, void* closure) { const char* value; - if (self->underlying_obj == NULL || arg == NULL) { + if (self->underlying_obj == NULL || self->document == NULL) { + PyErr_SetString(rapidxml_RapidXmlError, + "underlying mechanism failed"); + return -1; + } + if (arg == NULL) { + PyErr_SetString(PyExc_TypeError, + "value attribute must not be null"); return -1; } if (! @@ -99,7 +114,7 @@ static int rapidxml_BaseObject_setvalue(rapidxml_BaseObject* self, if (!PyArg_Parse(arg, "s", &value)) { return -1; } - self->underlying_obj->value(self->memory_pool.allocate_string(value)); + self->underlying_obj->value(self->document->allocate_string(value)); return 0; } diff --git a/src/node_object.cpp b/src/node_object.cpp index e3a687a..b595f62 100644 --- a/src/node_object.cpp +++ b/src/node_object.cpp @@ -42,6 +42,7 @@ static PyObject* rapidxml_NodeObject_first_node(rapidxml_NodeObject* self, new_node = (rapidxml_NodeObject*)PyObject_CallObject((PyObject*)&rapidxml_NodeType, NULL); new_node->base.underlying_obj = node; + new_node->base.document = self->base.document; return (PyObject*)new_node; } @@ -60,7 +61,7 @@ static PyObject* rapidxml_NodeObject_unparse(rapidxml_NodeObject* self, pretty = PyObject_IsTrue(pretty_obj); } rapidxml::print(std::back_inserter(xml), - *((rapidxml::xml_document<>*)self->base.underlying_obj), + *((rapidxml::xml_node<>*)self->base.underlying_obj), !pretty ? rapidxml::print_no_indenting : 0); return Py_BuildValue("s", xml.c_str()); } diff --git a/src/rapidxml_module.cpp b/src/rapidxml_module.cpp index 371f2bc..e3b44dc 100644 --- a/src/rapidxml_module.cpp +++ b/src/rapidxml_module.cpp @@ -12,7 +12,7 @@ #include -PyObject* RapidXmlError; +PyObject* rapidxml_RapidXmlError; static PyMethodDef module_methods[] = { {NULL} @@ -78,12 +78,12 @@ PyMODINIT_FUNC initrapidxml(void) "RapidXml", (PyObject *)&rapidxml_RapidXmlType); - RapidXmlError = PyErr_NewException("rapidxml.RapidXmlError", + rapidxml_RapidXmlError = PyErr_NewException("rapidxml.rapidxml_RapidXmlError", NULL, NULL); - Py_INCREF(RapidXmlError); + Py_INCREF(rapidxml_RapidXmlError); PyModule_AddObject(module, - "RapidXmlError", - RapidXmlError); + "rapidxml_RapidXmlError", + rapidxml_RapidXmlError); #if PY_MAJOR_VERSION >= 3 return module; diff --git a/src/rapidxml_object.cpp b/src/rapidxml_object.cpp index a58e1da..f11845b 100644 --- a/src/rapidxml_object.cpp +++ b/src/rapidxml_object.cpp @@ -48,18 +48,22 @@ static int rapidxml_RapidXmlObject_init(rapidxml_RapidXmlObject* self, if (from_file) { std::ifstream f(text, std::ios::binary); if (f.fail()) { - PyErr_SetString(RapidXmlError, strerror(errno)); + PyErr_SetString(rapidxml_RapidXmlError, strerror(errno)); return -1; } text_vector = std::vector((std::istreambuf_iterator(f)), std::istreambuf_iterator()); + text_vector.push_back(0); text = &text_vector[0]; } try { self->base.base.underlying_obj = new rapidxml::xml_document<>(); - ((rapidxml::xml_document<>*)self->base.base.underlying_obj)->parse(self->base.base.memory_pool.allocate_string(text)); + self->base.base.document = (rapidxml::xml_document<>*)self->base.base.underlying_obj; + (self->base.base.document + ->parse) + (self->base.base.document->allocate_string(text)); } catch (rapidxml::parse_error &e) { - PyErr_SetString(RapidXmlError, e.what()); + PyErr_SetString(rapidxml_RapidXmlError, e.what()); return -1; } return 0; diff --git a/test/simple.py b/test/simple.py new file mode 100755 index 0000000..866878b --- /dev/null +++ b/test/simple.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# File: simple.py +# by Arzaroth Lekva +# arzaroth@arzaroth.com +# +import rapidxml + +r = rapidxml.RapidXml("foo") # parsing from string +test = r.first_node("test") # get first node named test +assert(test.name == "test") +assert(test.value == "") +test.name = "foo" # changing node's name to foo +assert(test.name == "foo") + +test2 = r.first_node("test2") +assert(test2.name == "test2") +assert(test2.value == "foo") +test2.value = "bar" # changing node's value to bar +assert(test2.value == "bar") + +print(str(r)) # will output prettified string of the xml document +print(test) # also works for nodes + +with open('dump.xml', 'w') as f: + f.write(str(r)) +r = rapidxml.RapidXml("dump.xml", True) # loading from file + +assert(str(r) == r.unparse(True)) # is always True +assert(repr(r) == r.unparse()) # also always True, returns flat version From 9c8037cd9c0285c6952c80144a243913c53c50ab Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Tue, 14 Apr 2015 12:24:43 +0900 Subject: [PATCH 012/101] no more c casts --- src/base_object.cpp | 12 ++++++------ src/node_object.cpp | 21 +++++++++++---------- src/rapidxml_module.cpp | 6 +++--- src/rapidxml_object.cpp | 10 +++++----- 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/base_object.cpp b/src/base_object.cpp index 0c4f822..8cf20d8 100644 --- a/src/base_object.cpp +++ b/src/base_object.cpp @@ -14,7 +14,7 @@ #include static void rapidxml_BaseObject_dealloc(rapidxml_BaseObject* self) { - Py_TYPE(self)->tp_free((PyObject*)self); + Py_TYPE(self)->tp_free(reinterpret_cast(self)); } static PyObject* rapidxml_BaseObject_new(PyTypeObject* type, @@ -22,12 +22,12 @@ static PyObject* rapidxml_BaseObject_new(PyTypeObject* type, PyObject* kwds) { rapidxml_BaseObject* self; - self = (rapidxml_BaseObject*)type->tp_alloc(type, 0); + self = reinterpret_cast(type->tp_alloc(type, 0)); if (self != NULL) { self->underlying_obj = NULL; self->document = NULL; } - return (PyObject*)self; + return reinterpret_cast(self); } static int rapidxml_BaseObject_init(rapidxml_BaseObject* self, @@ -141,7 +141,7 @@ PyTypeObject rapidxml_BaseType = { "rapidxml.Base", /* tp_name */ sizeof(rapidxml_BaseObject), /* tp_basicsize */ 0, /* tp_itemsize */ - (destructor)rapidxml_BaseObject_dealloc, /* tp_dealloc */ + reinterpret_cast(rapidxml_BaseObject_dealloc), /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -172,9 +172,9 @@ PyTypeObject rapidxml_BaseType = { 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - (initproc)rapidxml_BaseObject_init, /* tp_init */ + reinterpret_cast(rapidxml_BaseObject_init), /* tp_init */ 0, /* tp_alloc */ - (newfunc)rapidxml_BaseObject_new, /* tp_new */ + reinterpret_cast(rapidxml_BaseObject_new), /* tp_new */ 0, /* tp_free */ 0, /* tp_is_gc */ 0, /* tp_bases */ diff --git a/src/node_object.cpp b/src/node_object.cpp index b595f62..612c16d 100644 --- a/src/node_object.cpp +++ b/src/node_object.cpp @@ -34,16 +34,17 @@ static PyObject* rapidxml_NodeObject_first_node(rapidxml_NodeObject* self, Py_INCREF(Py_None); return Py_None; } - rapidxml::xml_node<>* node = ((rapidxml::xml_node<>*)self->base.underlying_obj)->first_node(name); + rapidxml::xml_node<>* node = static_cast*>(self->base.underlying_obj)->first_node(name); if (!node) { Py_INCREF(Py_None); return Py_None; } - new_node = (rapidxml_NodeObject*)PyObject_CallObject((PyObject*)&rapidxml_NodeType, - NULL); + new_node = reinterpret_cast + (PyObject_CallObject(reinterpret_cast(&rapidxml_NodeType), + NULL)); new_node->base.underlying_obj = node; new_node->base.document = self->base.document; - return (PyObject*)new_node; + return reinterpret_cast(new_node); } static PyObject* rapidxml_NodeObject_unparse(rapidxml_NodeObject* self, @@ -61,7 +62,7 @@ static PyObject* rapidxml_NodeObject_unparse(rapidxml_NodeObject* self, pretty = PyObject_IsTrue(pretty_obj); } rapidxml::print(std::back_inserter(xml), - *((rapidxml::xml_node<>*)self->base.underlying_obj), + *(static_cast*>(self->base.underlying_obj)), !pretty ? rapidxml::print_no_indenting : 0); return Py_BuildValue("s", xml.c_str()); } @@ -91,9 +92,9 @@ static PyMemberDef rapidxml_NodeObject_members[] = { }; static PyMethodDef rapidxml_NodeObject_methods[] = { - {"first_node", (PyCFunction)rapidxml_NodeObject_first_node, + {"first_node", reinterpret_cast(rapidxml_NodeObject_first_node), METH_VARARGS | METH_KEYWORDS, "gets first child node, optionally matching node name"}, - {"unparse", (PyCFunction)rapidxml_NodeObject_unparse, + {"unparse", reinterpret_cast(rapidxml_NodeObject_unparse), METH_VARARGS | METH_KEYWORDS, "return xml string"}, {NULL} }; @@ -108,13 +109,13 @@ PyTypeObject rapidxml_NodeType = { 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ - (reprfunc)rapidxml_NodeObject___repr__, /* tp_repr */ + reinterpret_cast(rapidxml_NodeObject___repr__), /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ - (reprfunc)rapidxml_NodeObject___str__, /* tp_str */ + reinterpret_cast(rapidxml_NodeObject___str__), /* tp_repr */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ @@ -134,7 +135,7 @@ PyTypeObject rapidxml_NodeType = { 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - (initproc)rapidxml_NodeObject_init, /* tp_init */ + reinterpret_cast(rapidxml_NodeObject_init), /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ 0, /* tp_free */ diff --git a/src/rapidxml_module.cpp b/src/rapidxml_module.cpp index e3b44dc..0d15b21 100644 --- a/src/rapidxml_module.cpp +++ b/src/rapidxml_module.cpp @@ -66,17 +66,17 @@ PyMODINIT_FUNC initrapidxml(void) Py_INCREF(&rapidxml_BaseType); PyModule_AddObject(module, "Base", - (PyObject *)&rapidxml_BaseType); + reinterpret_cast(&rapidxml_BaseType)); Py_INCREF(&rapidxml_NodeType); PyModule_AddObject(module, "Node", - (PyObject *)&rapidxml_NodeType); + reinterpret_cast(&rapidxml_NodeType)); Py_INCREF(&rapidxml_RapidXmlType); PyModule_AddObject(module, "RapidXml", - (PyObject *)&rapidxml_RapidXmlType); + reinterpret_cast(&rapidxml_RapidXmlType)); rapidxml_RapidXmlError = PyErr_NewException("rapidxml.rapidxml_RapidXmlError", NULL, NULL); diff --git a/src/rapidxml_object.cpp b/src/rapidxml_object.cpp index f11845b..8e2b41a 100644 --- a/src/rapidxml_object.cpp +++ b/src/rapidxml_object.cpp @@ -20,7 +20,7 @@ static void rapidxml_RapidXmlObject_dealloc(rapidxml_RapidXmlObject* self) { free(self->base.base.underlying_obj); - Py_TYPE(self)->tp_free((PyObject*)self); + Py_TYPE(self)->tp_free(reinterpret_cast(self)); } static int rapidxml_RapidXmlObject_init(rapidxml_RapidXmlObject* self, @@ -33,7 +33,7 @@ static int rapidxml_RapidXmlObject_init(rapidxml_RapidXmlObject* self, char kw_from_file[] = "from_file"; std::vector text_vector; - if (rapidxml_NodeType.tp_init((PyObject*)self, args, kwds) < 0) { + if (rapidxml_NodeType.tp_init(reinterpret_cast(self), args, kwds) < 0) { return -1; } static char* kwlist[] = {kw_text, kw_from_file, NULL}; @@ -58,7 +58,7 @@ static int rapidxml_RapidXmlObject_init(rapidxml_RapidXmlObject* self, } try { self->base.base.underlying_obj = new rapidxml::xml_document<>(); - self->base.base.document = (rapidxml::xml_document<>*)self->base.base.underlying_obj; + self->base.base.document = static_cast*>(self->base.base.underlying_obj); (self->base.base.document ->parse) (self->base.base.document->allocate_string(text)); @@ -82,7 +82,7 @@ PyTypeObject rapidxml_RapidXmlType = { "rapidxml.RapidXml", /* tp_name */ sizeof(rapidxml_RapidXmlObject), /* tp_basicsize */ 0, /* tp_itemsize */ - (destructor)rapidxml_RapidXmlObject_dealloc, /* tp_dealloc */ + reinterpret_cast(rapidxml_RapidXmlObject_dealloc), /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -113,7 +113,7 @@ PyTypeObject rapidxml_RapidXmlType = { 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - (initproc)rapidxml_RapidXmlObject_init, /* tp_init */ + reinterpret_cast(rapidxml_RapidXmlObject_init), /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ 0, /* tp_free */ From 382524f604536b25ed1264049a9e1bf36fb1f778 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Tue, 14 Apr 2015 12:50:39 +0900 Subject: [PATCH 013/101] using base init in node --- src/node_object.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node_object.cpp b/src/node_object.cpp index 612c16d..e91372d 100644 --- a/src/node_object.cpp +++ b/src/node_object.cpp @@ -18,7 +18,7 @@ static int rapidxml_NodeObject_init(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { - return 0; + return rapidxml_BaseType.tp_init(reinterpret_cast(self), args, kwds); } static PyObject* rapidxml_NodeObject_first_node(rapidxml_NodeObject* self, From a8bfbeda3c664d8fc64fdcc02a209d0d03f0fba7 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Tue, 14 Apr 2015 14:07:42 +0900 Subject: [PATCH 014/101] attribute type --- inc/common.h | 5 ++ setup.py | 1 + src/attribute_object.cpp | 144 +++++++++++++++++++++++++++++++++++++++ src/node_object.cpp | 65 ++++++++++++++---- src/rapidxml_module.cpp | 8 +++ 5 files changed, 210 insertions(+), 13 deletions(-) create mode 100644 src/attribute_object.cpp diff --git a/inc/common.h b/inc/common.h index dd37eb9..dd42555 100644 --- a/inc/common.h +++ b/inc/common.h @@ -22,12 +22,17 @@ typedef struct { rapidxml_BaseObject base; } rapidxml_NodeObject; +typedef struct { + rapidxml_BaseObject base; +} rapidxml_AttributeObject; + typedef struct { rapidxml_NodeObject base; } rapidxml_RapidXmlObject; extern PyTypeObject rapidxml_BaseType; extern PyTypeObject rapidxml_NodeType; +extern PyTypeObject rapidxml_AttributeType; extern PyTypeObject rapidxml_RapidXmlType; extern PyObject* rapidxml_RapidXmlError; diff --git a/setup.py b/setup.py index 90b5c0f..dc806dd 100644 --- a/setup.py +++ b/setup.py @@ -16,6 +16,7 @@ "./src/rapidxml_module.cpp", "./src/base_object.cpp", "./src/node_object.cpp", + "./src/attribute_object.cpp", "./src/rapidxml_object.cpp", ], ) diff --git a/src/attribute_object.cpp b/src/attribute_object.cpp new file mode 100644 index 0000000..b10498a --- /dev/null +++ b/src/attribute_object.cpp @@ -0,0 +1,144 @@ +/* +** -*- coding: utf-8 -*- +** +** File: attribute_object.cpp +** by Arzaroth Lekva +** arzaroth@arzaroth.com +** +*/ + +#include +#include +#include +#include + +#include + +static int rapidxml_AttributeObject_init(rapidxml_AttributeObject* self, + PyObject* args, + PyObject* kwds) { + return rapidxml_BaseType.tp_init(reinterpret_cast(self), args, kwds); +} + +static int _parse_args_for_name(PyObject* args, + PyObject* kwds, + const char** name) { + char kw_name[] = "name"; + + static char* kwlist[] = {kw_name, NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist, + name)) { + return false; + } + return true; +} + +static PyObject* _bind_result(rapidxml_AttributeObject* self, + rapidxml::xml_attribute<>* attribute) { + rapidxml_AttributeObject* new_attribute; + + new_attribute = reinterpret_cast + (PyObject_CallObject(reinterpret_cast(&rapidxml_AttributeType), + NULL)); + new_attribute->base.underlying_obj = attribute; + new_attribute->base.document = self->base.document; + return reinterpret_cast(new_attribute); +} + +static PyObject* rapidxml_AttributeObject_previous_attribute(rapidxml_AttributeObject* self, + PyObject* args, + PyObject* kwds) { + const char* name = NULL; + rapidxml::xml_attribute<>* attribute; + + if (!_parse_args_for_name(args, kwds, &name)) { + goto err; + } + attribute = static_cast*>(self->base.underlying_obj)->previous_attribute(name); + if (attribute == NULL) { + goto err; + } + return _bind_result(self, attribute); + err: + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* rapidxml_AttributeObject_next_attribute(rapidxml_AttributeObject* self, + PyObject* args, + PyObject* kwds) { + const char* name = NULL; + rapidxml::xml_attribute<>* attribute; + + if (!_parse_args_for_name(args, kwds, &name)) { + goto err; + } + attribute = static_cast*>(self->base.underlying_obj)->next_attribute(name); + if (attribute == NULL) { + goto err; + } + return _bind_result(self, attribute); + err: + Py_INCREF(Py_None); + return Py_None; +} + +static PyMemberDef rapidxml_AttributeObject_members[] = { + {NULL} +}; + +static PyMethodDef rapidxml_AttributeObject_methods[] = { + {"previous_attribute", reinterpret_cast(rapidxml_AttributeObject_previous_attribute), + METH_VARARGS | METH_KEYWORDS, "gets previous attribute, optionally matching attribute name"}, + {"next_attribute", reinterpret_cast(rapidxml_AttributeObject_next_attribute), + METH_VARARGS | METH_KEYWORDS, "gets next attribute, optionally matching attribute name"}, + {NULL} +}; + +PyTypeObject rapidxml_AttributeType = { + PyVarObject_HEAD_INIT(NULL, 0) + "rapidxml.Attribute", /* tp_name */ + sizeof(rapidxml_AttributeObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_repr */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "class representing a rapidxml::xml_attribute", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + rapidxml_AttributeObject_methods, /* tp_methods */ + rapidxml_AttributeObject_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + reinterpret_cast(rapidxml_AttributeObject_init), /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +}; diff --git a/src/node_object.cpp b/src/node_object.cpp index e91372d..4d60681 100644 --- a/src/node_object.cpp +++ b/src/node_object.cpp @@ -21,24 +21,23 @@ static int rapidxml_NodeObject_init(rapidxml_NodeObject* self, return rapidxml_BaseType.tp_init(reinterpret_cast(self), args, kwds); } -static PyObject* rapidxml_NodeObject_first_node(rapidxml_NodeObject* self, - PyObject* args, - PyObject* kwds) { - const char* name = NULL; - rapidxml_NodeObject* new_node; +static int _parse_args_for_name(PyObject* args, + PyObject* kwds, + const char** name) { char kw_name[] = "name"; static char* kwlist[] = {kw_name, NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist, - &name)) { - Py_INCREF(Py_None); - return Py_None; - } - rapidxml::xml_node<>* node = static_cast*>(self->base.underlying_obj)->first_node(name); - if (!node) { - Py_INCREF(Py_None); - return Py_None; + name)) { + return false; } + return true; +} + +static PyObject* _bind_result(rapidxml_NodeObject* self, + rapidxml::xml_node<>* node) { + rapidxml_NodeObject* new_node; + new_node = reinterpret_cast (PyObject_CallObject(reinterpret_cast(&rapidxml_NodeType), NULL)); @@ -47,6 +46,44 @@ static PyObject* rapidxml_NodeObject_first_node(rapidxml_NodeObject* self, return reinterpret_cast(new_node); } +static PyObject* rapidxml_NodeObject_first_node(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + const char* name = NULL; + rapidxml::xml_node<>* node; + + if (!_parse_args_for_name(args, kwds, &name)) { + goto err; + } + node = static_cast*>(self->base.underlying_obj)->first_node(name); + if (node == NULL) { + goto err; + } + return _bind_result(self, node); + err: + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* rapidxml_NodeObject_last_node(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + const char* name = NULL; + rapidxml::xml_node<>* node; + + if (!_parse_args_for_name(args, kwds, &name)) { + goto err; + } + node = static_cast*>(self->base.underlying_obj)->last_node(name); + if (node == NULL) { + goto err; + } + return _bind_result(self, node); + err: + Py_INCREF(Py_None); + return Py_None; +} + static PyObject* rapidxml_NodeObject_unparse(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { @@ -94,6 +131,8 @@ static PyMemberDef rapidxml_NodeObject_members[] = { static PyMethodDef rapidxml_NodeObject_methods[] = { {"first_node", reinterpret_cast(rapidxml_NodeObject_first_node), METH_VARARGS | METH_KEYWORDS, "gets first child node, optionally matching node name"}, + {"last_node", reinterpret_cast(rapidxml_NodeObject_last_node), + METH_VARARGS | METH_KEYWORDS, "gets last child node, optionally matching node name"}, {"unparse", reinterpret_cast(rapidxml_NodeObject_unparse), METH_VARARGS | METH_KEYWORDS, "return xml string"}, {NULL} diff --git a/src/rapidxml_module.cpp b/src/rapidxml_module.cpp index 0d15b21..d17bb07 100644 --- a/src/rapidxml_module.cpp +++ b/src/rapidxml_module.cpp @@ -49,6 +49,9 @@ PyMODINIT_FUNC initrapidxml(void) rapidxml_NodeType.tp_base = &rapidxml_BaseType; if (PyType_Ready(&rapidxml_NodeType) < 0) INITERROR; + rapidxml_AttributeType.tp_base = &rapidxml_BaseType; + if (PyType_Ready(&rapidxml_AttributeType) < 0) + INITERROR; rapidxml_RapidXmlType.tp_base = &rapidxml_NodeType; if (PyType_Ready(&rapidxml_RapidXmlType) < 0) INITERROR; @@ -73,6 +76,11 @@ PyMODINIT_FUNC initrapidxml(void) "Node", reinterpret_cast(&rapidxml_NodeType)); + Py_INCREF(&rapidxml_AttributeType); + PyModule_AddObject(module, + "Attribute", + reinterpret_cast(&rapidxml_AttributeType)); + Py_INCREF(&rapidxml_RapidXmlType); PyModule_AddObject(module, "RapidXml", From 598f5e8a7d11b6368332b2398ca2958af9ab5d23 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Tue, 14 Apr 2015 14:09:57 +0900 Subject: [PATCH 015/101] node siblings --- src/node_object.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/node_object.cpp b/src/node_object.cpp index 4d60681..9595bf4 100644 --- a/src/node_object.cpp +++ b/src/node_object.cpp @@ -84,6 +84,44 @@ static PyObject* rapidxml_NodeObject_last_node(rapidxml_NodeObject* self, return Py_None; } +static PyObject* rapidxml_NodeObject_previous_sibling(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + const char* name = NULL; + rapidxml::xml_node<>* node; + + if (!_parse_args_for_name(args, kwds, &name)) { + goto err; + } + node = static_cast*>(self->base.underlying_obj)->previous_sibling(name); + if (node == NULL) { + goto err; + } + return _bind_result(self, node); + err: + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* rapidxml_NodeObject_next_sibling(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + const char* name = NULL; + rapidxml::xml_node<>* node; + + if (!_parse_args_for_name(args, kwds, &name)) { + goto err; + } + node = static_cast*>(self->base.underlying_obj)->next_sibling(name); + if (node == NULL) { + goto err; + } + return _bind_result(self, node); + err: + Py_INCREF(Py_None); + return Py_None; +} + static PyObject* rapidxml_NodeObject_unparse(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { @@ -133,6 +171,10 @@ static PyMethodDef rapidxml_NodeObject_methods[] = { METH_VARARGS | METH_KEYWORDS, "gets first child node, optionally matching node name"}, {"last_node", reinterpret_cast(rapidxml_NodeObject_last_node), METH_VARARGS | METH_KEYWORDS, "gets last child node, optionally matching node name"}, + {"previous_sibling", reinterpret_cast(rapidxml_NodeObject_previous_sibling), + METH_VARARGS | METH_KEYWORDS, "gets previous sibling node, optionally matching node name"}, + {"next_sibling", reinterpret_cast(rapidxml_NodeObject_next_sibling), + METH_VARARGS | METH_KEYWORDS, "gets next sibling node, optionally matching node name"}, {"unparse", reinterpret_cast(rapidxml_NodeObject_unparse), METH_VARARGS | METH_KEYWORDS, "return xml string"}, {NULL} From 2c0c970dbc110311303ddb4cf8e212fb2fc9d905 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Tue, 14 Apr 2015 14:35:54 +0900 Subject: [PATCH 016/101] node attributes, utility functions --- inc/common.h | 3 ++ setup.py | 1 + src/attribute_object.cpp | 31 ++------------- src/common.cpp | 40 ++++++++++++++++++++ src/node_object.cpp | 81 ++++++++++++++++++++++++++-------------- 5 files changed, 100 insertions(+), 56 deletions(-) create mode 100644 src/common.cpp diff --git a/inc/common.h b/inc/common.h index dd42555..d44275a 100644 --- a/inc/common.h +++ b/inc/common.h @@ -37,4 +37,7 @@ extern PyTypeObject rapidxml_RapidXmlType; extern PyObject* rapidxml_RapidXmlError; +int _parse_args_for_name(PyObject*, PyObject*, const char**); +PyObject* _bind_result(rapidxml_BaseObject*, rapidxml::xml_base<>*, PyTypeObject*); + #endif /* !COMMON_H_ */ diff --git a/setup.py b/setup.py index dc806dd..3228ea3 100644 --- a/setup.py +++ b/setup.py @@ -13,6 +13,7 @@ ('MINOR_VERSION', '0')], include_dirs=['./rapidxml-1.13/', './inc/'], sources=[ + "./src/common.cpp", "./src/rapidxml_module.cpp", "./src/base_object.cpp", "./src/node_object.cpp", diff --git a/src/attribute_object.cpp b/src/attribute_object.cpp index b10498a..ffd856e 100644 --- a/src/attribute_object.cpp +++ b/src/attribute_object.cpp @@ -20,31 +20,6 @@ static int rapidxml_AttributeObject_init(rapidxml_AttributeObject* self, return rapidxml_BaseType.tp_init(reinterpret_cast(self), args, kwds); } -static int _parse_args_for_name(PyObject* args, - PyObject* kwds, - const char** name) { - char kw_name[] = "name"; - - static char* kwlist[] = {kw_name, NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist, - name)) { - return false; - } - return true; -} - -static PyObject* _bind_result(rapidxml_AttributeObject* self, - rapidxml::xml_attribute<>* attribute) { - rapidxml_AttributeObject* new_attribute; - - new_attribute = reinterpret_cast - (PyObject_CallObject(reinterpret_cast(&rapidxml_AttributeType), - NULL)); - new_attribute->base.underlying_obj = attribute; - new_attribute->base.document = self->base.document; - return reinterpret_cast(new_attribute); -} - static PyObject* rapidxml_AttributeObject_previous_attribute(rapidxml_AttributeObject* self, PyObject* args, PyObject* kwds) { @@ -58,7 +33,8 @@ static PyObject* rapidxml_AttributeObject_previous_attribute(rapidxml_AttributeO if (attribute == NULL) { goto err; } - return _bind_result(self, attribute); + return _bind_result(reinterpret_cast(self), + attribute, &rapidxml_AttributeType); err: Py_INCREF(Py_None); return Py_None; @@ -77,7 +53,8 @@ static PyObject* rapidxml_AttributeObject_next_attribute(rapidxml_AttributeObjec if (attribute == NULL) { goto err; } - return _bind_result(self, attribute); + return _bind_result(reinterpret_cast(self), + attribute, &rapidxml_AttributeType); err: Py_INCREF(Py_None); return Py_None; diff --git a/src/common.cpp b/src/common.cpp new file mode 100644 index 0000000..154272b --- /dev/null +++ b/src/common.cpp @@ -0,0 +1,40 @@ +/* +** -*- coding: utf-8 -*- +** +** File: common.cpp +** by Arzaroth Lekva +** arzaroth@arzaroth.com +** +*/ + +#include +#include +#include + +#include + +int _parse_args_for_name(PyObject* args, + PyObject* kwds, + const char** name) { + char kw_name[] = "name"; + + static char* kwlist[] = {kw_name, NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist, + name)) { + return false; + } + return true; +} + +PyObject* _bind_result(rapidxml_BaseObject* self, + rapidxml::xml_base<>* base, + PyTypeObject* type) { + rapidxml_BaseObject* new_base; + + new_base = reinterpret_cast + (PyObject_CallObject(reinterpret_cast(type), + NULL)); + new_base->underlying_obj = base; + new_base->document = self->document; + return reinterpret_cast(new_base); +} diff --git a/src/node_object.cpp b/src/node_object.cpp index 9595bf4..030ca1e 100644 --- a/src/node_object.cpp +++ b/src/node_object.cpp @@ -21,31 +21,6 @@ static int rapidxml_NodeObject_init(rapidxml_NodeObject* self, return rapidxml_BaseType.tp_init(reinterpret_cast(self), args, kwds); } -static int _parse_args_for_name(PyObject* args, - PyObject* kwds, - const char** name) { - char kw_name[] = "name"; - - static char* kwlist[] = {kw_name, NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist, - name)) { - return false; - } - return true; -} - -static PyObject* _bind_result(rapidxml_NodeObject* self, - rapidxml::xml_node<>* node) { - rapidxml_NodeObject* new_node; - - new_node = reinterpret_cast - (PyObject_CallObject(reinterpret_cast(&rapidxml_NodeType), - NULL)); - new_node->base.underlying_obj = node; - new_node->base.document = self->base.document; - return reinterpret_cast(new_node); -} - static PyObject* rapidxml_NodeObject_first_node(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { @@ -59,7 +34,8 @@ static PyObject* rapidxml_NodeObject_first_node(rapidxml_NodeObject* self, if (node == NULL) { goto err; } - return _bind_result(self, node); + return _bind_result(reinterpret_cast(self), + node, &rapidxml_NodeType); err: Py_INCREF(Py_None); return Py_None; @@ -78,7 +54,8 @@ static PyObject* rapidxml_NodeObject_last_node(rapidxml_NodeObject* self, if (node == NULL) { goto err; } - return _bind_result(self, node); + return _bind_result(reinterpret_cast(self), + node, &rapidxml_NodeType); err: Py_INCREF(Py_None); return Py_None; @@ -97,7 +74,8 @@ static PyObject* rapidxml_NodeObject_previous_sibling(rapidxml_NodeObject* self, if (node == NULL) { goto err; } - return _bind_result(self, node); + return _bind_result(reinterpret_cast(self), + node, &rapidxml_NodeType); err: Py_INCREF(Py_None); return Py_None; @@ -116,7 +94,48 @@ static PyObject* rapidxml_NodeObject_next_sibling(rapidxml_NodeObject* self, if (node == NULL) { goto err; } - return _bind_result(self, node); + return _bind_result(reinterpret_cast(self), + node, &rapidxml_NodeType); + err: + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* rapidxml_NodeObject_first_attribute(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + const char* name = NULL; + rapidxml::xml_attribute<>* attribute; + + if (!_parse_args_for_name(args, kwds, &name)) { + goto err; + } + attribute = static_cast*>(self->base.underlying_obj)->first_attribute(name); + if (attribute == NULL) { + goto err; + } + return _bind_result(reinterpret_cast(self), + attribute, &rapidxml_AttributeType); + err: + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* rapidxml_NodeObject_last_attribute(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + const char* name = NULL; + rapidxml::xml_attribute<>* attribute; + + if (!_parse_args_for_name(args, kwds, &name)) { + goto err; + } + attribute = static_cast*>(self->base.underlying_obj)->last_attribute(name); + if (attribute == NULL) { + goto err; + } + return _bind_result(reinterpret_cast(self), + attribute, &rapidxml_AttributeType); err: Py_INCREF(Py_None); return Py_None; @@ -175,6 +194,10 @@ static PyMethodDef rapidxml_NodeObject_methods[] = { METH_VARARGS | METH_KEYWORDS, "gets previous sibling node, optionally matching node name"}, {"next_sibling", reinterpret_cast(rapidxml_NodeObject_next_sibling), METH_VARARGS | METH_KEYWORDS, "gets next sibling node, optionally matching node name"}, + {"first_attribute", reinterpret_cast(rapidxml_NodeObject_first_attribute), + METH_VARARGS | METH_KEYWORDS, "gets first attribute of node, optionally matching node name"}, + {"last_attribute", reinterpret_cast(rapidxml_NodeObject_last_attribute), + METH_VARARGS | METH_KEYWORDS, "gets last attribute of node, optionally matching node name"}, {"unparse", reinterpret_cast(rapidxml_NodeObject_unparse), METH_VARARGS | METH_KEYWORDS, "return xml string"}, {NULL} From 87064aca1f258f675e45ea45f32e8c7c13c50166 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Tue, 14 Apr 2015 17:05:22 +0900 Subject: [PATCH 017/101] allocate node & attribute --- src/rapidxml_object.cpp | 46 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/rapidxml_object.cpp b/src/rapidxml_object.cpp index 8e2b41a..739f738 100644 --- a/src/rapidxml_object.cpp +++ b/src/rapidxml_object.cpp @@ -19,7 +19,7 @@ #include static void rapidxml_RapidXmlObject_dealloc(rapidxml_RapidXmlObject* self) { - free(self->base.base.underlying_obj); + delete self->base.base.underlying_obj; Py_TYPE(self)->tp_free(reinterpret_cast(self)); } @@ -69,11 +69,55 @@ static int rapidxml_RapidXmlObject_init(rapidxml_RapidXmlObject* self, return 0; } +static PyObject* rapidxml_RapidXmlObject_allocate_node(rapidxml_RapidXmlObject* self, + PyObject* args, + PyObject* kwds) { + const char* name = NULL; + const char* value = NULL; + char kw_name[] = "name"; + char kw_value[] = "value"; + rapidxml::xml_node<>* node; + + static char* kwlist[] = {kw_name, kw_value, NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ss", kwlist, + &name, &value)) { + Py_INCREF(Py_None); + return Py_None; + } + node = self->base.base.document->allocate_node(rapidxml::node_element, name, value); + return _bind_result(reinterpret_cast(self), + node, &rapidxml_NodeType); +} + +static PyObject* rapidxml_RapidXmlObject_allocate_attribute(rapidxml_RapidXmlObject* self, + PyObject* args, + PyObject* kwds) { + const char* name = NULL; + const char* value = NULL; + char kw_name[] = "name"; + char kw_value[] = "value"; + rapidxml::xml_attribute<>* attribute; + + static char* kwlist[] = {kw_name, kw_value, NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ss", kwlist, + &name, &value)) { + Py_INCREF(Py_None); + return Py_None; + } + attribute = self->base.base.document->allocate_attribute(name, value); + return _bind_result(reinterpret_cast(self), + attribute, &rapidxml_AttributeType); +} + static PyMemberDef rapidxml_RapidXmlObject_members[] = { {NULL} }; static PyMethodDef rapidxml_RapidXmlObject_methods[] = { + {"allocate_node", reinterpret_cast(rapidxml_RapidXmlObject_allocate_node), + METH_VARARGS | METH_KEYWORDS, "allocates a new node from the pool, and optionally assigns name and value to it"}, + {"allocate_attribute", reinterpret_cast(rapidxml_RapidXmlObject_allocate_attribute), + METH_VARARGS | METH_KEYWORDS, "allocates a new attribute from the pool, and optionally assigns name and value to it"}, {NULL} }; From c27aa949419f47f08a594cae351136d863d69214 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Wed, 15 Apr 2015 06:48:46 +0900 Subject: [PATCH 018/101] node iterator --- inc/common.h | 32 +++++++++++ setup.py | 1 + src/node_object.cpp | 22 +++++++- src/nodeiterator_object.cpp | 107 ++++++++++++++++++++++++++++++++++++ src/rapidxml_module.cpp | 8 +++ 5 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 src/nodeiterator_object.cpp diff --git a/inc/common.h b/inc/common.h index d44275a..02e3dac 100644 --- a/inc/common.h +++ b/inc/common.h @@ -12,6 +12,14 @@ # include +# if PY_MAJOR_VERSION >= 3 +# define Py_TPFLAGS_HAVE_ITER 0 +# endif + +/* +** Objects definitions +*/ + typedef struct { PyObject_HEAD rapidxml::xml_base<>* underlying_obj; @@ -30,13 +38,37 @@ typedef struct { rapidxml_NodeObject base; } rapidxml_RapidXmlObject; +/* +** Iterators definitions +*/ + +typedef struct { + PyObject_HEAD + PyObject* parent; + rapidxml::xml_node<>* node; +} rapidxml_NodeIteratorObject; + +/* +** Types +*/ + extern PyTypeObject rapidxml_BaseType; extern PyTypeObject rapidxml_NodeType; extern PyTypeObject rapidxml_AttributeType; extern PyTypeObject rapidxml_RapidXmlType; +extern PyTypeObject rapidxml_NodeIteratorType; + +/* +** Exceptions +*/ + extern PyObject* rapidxml_RapidXmlError; +/* +** Utility functions +*/ + int _parse_args_for_name(PyObject*, PyObject*, const char**); PyObject* _bind_result(rapidxml_BaseObject*, rapidxml::xml_base<>*, PyTypeObject*); diff --git a/setup.py b/setup.py index 3228ea3..04846b8 100644 --- a/setup.py +++ b/setup.py @@ -19,6 +19,7 @@ "./src/node_object.cpp", "./src/attribute_object.cpp", "./src/rapidxml_object.cpp", + "./src/nodeiterator_object.cpp", ], ) diff --git a/src/node_object.cpp b/src/node_object.cpp index 030ca1e..d406096 100644 --- a/src/node_object.cpp +++ b/src/node_object.cpp @@ -181,6 +181,26 @@ static PyObject* rapidxml_NodeObject___repr__(rapidxml_NodeObject* self) { return res; } +static PyObject* rapidxml_NodeObject_children(rapidxml_NodeObject* self, + void* closure) { + rapidxml_NodeIteratorObject* iterator; + PyObject* args; + + args = Py_BuildValue("(O)", self); + iterator = reinterpret_cast + (PyObject_CallObject(reinterpret_cast(&rapidxml_NodeIteratorType), + args)); + Py_DECREF(args); + return reinterpret_cast(iterator); +} + +static PyGetSetDef rapidxml_NodeObject_getseters[] = { + {"children", + (getter)rapidxml_NodeObject_children, NULL, + "return an NodeIteratorObject to iterate over a node's children"}, + {NULL} +}; + static PyMemberDef rapidxml_NodeObject_members[] = { {NULL} }; @@ -233,7 +253,7 @@ PyTypeObject rapidxml_NodeType = { 0, /* tp_iternext */ rapidxml_NodeObject_methods, /* tp_methods */ rapidxml_NodeObject_members, /* tp_members */ - 0, /* tp_getset */ + rapidxml_NodeObject_getseters, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ diff --git a/src/nodeiterator_object.cpp b/src/nodeiterator_object.cpp new file mode 100644 index 0000000..bcf8ee0 --- /dev/null +++ b/src/nodeiterator_object.cpp @@ -0,0 +1,107 @@ +/* +** -*- coding: utf-8 -*- +** +** File: nodeiterator_object.cpp +** by Arzaroth Lekva +** arzaroth@arzaroth.com +** +*/ + +#include +#include +#include + +#include + +static void rapidxml_NodeIteratorObject_dealloc(rapidxml_NodeIteratorObject* self) { + Py_XDECREF(self->parent); + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} + +static PyObject* rapidxml_NodeIteratorObject_new(PyTypeObject* type, + PyObject* args, + PyObject* kwds) { + rapidxml_NodeIteratorObject* self; + + self = reinterpret_cast(type->tp_alloc(type, 0)); + if (self != NULL) { + self->node = NULL; + self->parent = NULL; + if (!PyArg_ParseTuple(args, "O", &self->parent)) { + Py_DECREF(self); + return NULL; + } + if (self->parent != NULL) { + Py_INCREF(self->parent); + self->node = static_cast*> + (reinterpret_cast(self->parent) + ->base.underlying_obj)->first_node(); + } + } + return reinterpret_cast(self); +} + +static PyObject* rapidxml_NodeIteratorObject_iter(rapidxml_NodeIteratorObject* self) { + Py_INCREF(self); + return reinterpret_cast(self); +} + +static PyObject* rapidxml_NodeIteratorObject_iternext(rapidxml_NodeIteratorObject* self) { + PyObject* res; + + if (self->node == NULL || self->parent == NULL) { + return NULL; + } + res = _bind_result(reinterpret_cast(self->parent), + self->node, &rapidxml_NodeType); + self->node = self->node->next_sibling(); + return res; +} + +PyTypeObject rapidxml_NodeIteratorType = { + PyVarObject_HEAD_INIT(NULL, 0) + "rapidxml.NodeIterator", /* tp_name */ + sizeof(rapidxml_NodeIteratorObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + reinterpret_cast(rapidxml_NodeIteratorObject_dealloc), /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_repr */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /* tp_flags */ + "class for iterating over a Node object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + reinterpret_cast(rapidxml_NodeIteratorObject_iter), /* tp_iter */ + reinterpret_cast(rapidxml_NodeIteratorObject_iternext), /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + reinterpret_cast(rapidxml_NodeIteratorObject_new), /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +}; diff --git a/src/rapidxml_module.cpp b/src/rapidxml_module.cpp index d17bb07..8f40fa8 100644 --- a/src/rapidxml_module.cpp +++ b/src/rapidxml_module.cpp @@ -56,6 +56,9 @@ PyMODINIT_FUNC initrapidxml(void) if (PyType_Ready(&rapidxml_RapidXmlType) < 0) INITERROR; + if (PyType_Ready(&rapidxml_NodeIteratorType) < 0) + INITERROR; + #if PY_MAJOR_VERSION >= 3 module = PyModule_Create(&moduledef); #else @@ -86,6 +89,11 @@ PyMODINIT_FUNC initrapidxml(void) "RapidXml", reinterpret_cast(&rapidxml_RapidXmlType)); + Py_INCREF(&rapidxml_NodeIteratorType); + PyModule_AddObject(module, + "NodeIterator", + reinterpret_cast(&rapidxml_NodeIteratorType)); + rapidxml_RapidXmlError = PyErr_NewException("rapidxml.rapidxml_RapidXmlError", NULL, NULL); Py_INCREF(rapidxml_RapidXmlError); From 24014804bb07cc90dd300742f7489471bf4cd9a9 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Wed, 15 Apr 2015 06:50:57 +0900 Subject: [PATCH 019/101] node iterator new --- src/nodeiterator_object.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/nodeiterator_object.cpp b/src/nodeiterator_object.cpp index bcf8ee0..802853b 100644 --- a/src/nodeiterator_object.cpp +++ b/src/nodeiterator_object.cpp @@ -27,15 +27,15 @@ static PyObject* rapidxml_NodeIteratorObject_new(PyTypeObject* type, if (self != NULL) { self->node = NULL; self->parent = NULL; - if (!PyArg_ParseTuple(args, "O", &self->parent)) { - Py_DECREF(self); - return NULL; - } - if (self->parent != NULL) { + if (PyArg_ParseTuple(args, "O", &self->parent) && + self->parent != NULL) { Py_INCREF(self->parent); self->node = static_cast*> (reinterpret_cast(self->parent) ->base.underlying_obj)->first_node(); + } else { + Py_DECREF(self); + return NULL; } } return reinterpret_cast(self); From 5da719138fbd1d7caf85fdbff9f2397857bd8af8 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Wed, 15 Apr 2015 06:53:26 +0900 Subject: [PATCH 020/101] renaming RapidXml object to Document --- inc/common.h | 4 +-- setup.py | 2 +- ...apidxml_object.cpp => document_object.cpp} | 32 +++++++++---------- src/rapidxml_module.cpp | 10 +++--- 4 files changed, 24 insertions(+), 24 deletions(-) rename src/{rapidxml_object.cpp => document_object.cpp} (85%) diff --git a/inc/common.h b/inc/common.h index 02e3dac..d5471f3 100644 --- a/inc/common.h +++ b/inc/common.h @@ -36,7 +36,7 @@ typedef struct { typedef struct { rapidxml_NodeObject base; -} rapidxml_RapidXmlObject; +} rapidxml_DocumentObject; /* ** Iterators definitions @@ -55,7 +55,7 @@ typedef struct { extern PyTypeObject rapidxml_BaseType; extern PyTypeObject rapidxml_NodeType; extern PyTypeObject rapidxml_AttributeType; -extern PyTypeObject rapidxml_RapidXmlType; +extern PyTypeObject rapidxml_DocumentType; extern PyTypeObject rapidxml_NodeIteratorType; diff --git a/setup.py b/setup.py index 04846b8..54dbb36 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ "./src/base_object.cpp", "./src/node_object.cpp", "./src/attribute_object.cpp", - "./src/rapidxml_object.cpp", + "./src/document_object.cpp", "./src/nodeiterator_object.cpp", ], ) diff --git a/src/rapidxml_object.cpp b/src/document_object.cpp similarity index 85% rename from src/rapidxml_object.cpp rename to src/document_object.cpp index 739f738..533d8ce 100644 --- a/src/rapidxml_object.cpp +++ b/src/document_object.cpp @@ -1,7 +1,7 @@ /* ** -*- coding: utf-8 -*- ** -** File: rapidxml_object.cpp +** File: document_object.cpp ** by Arzaroth Lekva ** arzaroth@arzaroth.com ** @@ -18,12 +18,12 @@ #include -static void rapidxml_RapidXmlObject_dealloc(rapidxml_RapidXmlObject* self) { +static void rapidxml_DocumentObject_dealloc(rapidxml_DocumentObject* self) { delete self->base.base.underlying_obj; Py_TYPE(self)->tp_free(reinterpret_cast(self)); } -static int rapidxml_RapidXmlObject_init(rapidxml_RapidXmlObject* self, +static int rapidxml_DocumentObject_init(rapidxml_DocumentObject* self, PyObject* args, PyObject* kwds) { const char* text; @@ -69,7 +69,7 @@ static int rapidxml_RapidXmlObject_init(rapidxml_RapidXmlObject* self, return 0; } -static PyObject* rapidxml_RapidXmlObject_allocate_node(rapidxml_RapidXmlObject* self, +static PyObject* rapidxml_DocumentObject_allocate_node(rapidxml_DocumentObject* self, PyObject* args, PyObject* kwds) { const char* name = NULL; @@ -89,7 +89,7 @@ static PyObject* rapidxml_RapidXmlObject_allocate_node(rapidxml_RapidXmlObject* node, &rapidxml_NodeType); } -static PyObject* rapidxml_RapidXmlObject_allocate_attribute(rapidxml_RapidXmlObject* self, +static PyObject* rapidxml_DocumentObject_allocate_attribute(rapidxml_DocumentObject* self, PyObject* args, PyObject* kwds) { const char* name = NULL; @@ -109,24 +109,24 @@ static PyObject* rapidxml_RapidXmlObject_allocate_attribute(rapidxml_RapidXmlObj attribute, &rapidxml_AttributeType); } -static PyMemberDef rapidxml_RapidXmlObject_members[] = { +static PyMemberDef rapidxml_DocumentObject_members[] = { {NULL} }; -static PyMethodDef rapidxml_RapidXmlObject_methods[] = { - {"allocate_node", reinterpret_cast(rapidxml_RapidXmlObject_allocate_node), +static PyMethodDef rapidxml_DocumentObject_methods[] = { + {"allocate_node", reinterpret_cast(rapidxml_DocumentObject_allocate_node), METH_VARARGS | METH_KEYWORDS, "allocates a new node from the pool, and optionally assigns name and value to it"}, - {"allocate_attribute", reinterpret_cast(rapidxml_RapidXmlObject_allocate_attribute), + {"allocate_attribute", reinterpret_cast(rapidxml_DocumentObject_allocate_attribute), METH_VARARGS | METH_KEYWORDS, "allocates a new attribute from the pool, and optionally assigns name and value to it"}, {NULL} }; -PyTypeObject rapidxml_RapidXmlType = { +PyTypeObject rapidxml_DocumentType = { PyVarObject_HEAD_INIT(NULL, 0) - "rapidxml.RapidXml", /* tp_name */ - sizeof(rapidxml_RapidXmlObject), /* tp_basicsize */ + "rapidxml.Document", /* tp_name */ + sizeof(rapidxml_DocumentObject), /* tp_basicsize */ 0, /* tp_itemsize */ - reinterpret_cast(rapidxml_RapidXmlObject_dealloc), /* tp_dealloc */ + reinterpret_cast(rapidxml_DocumentObject_dealloc), /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -149,15 +149,15 @@ PyTypeObject rapidxml_RapidXmlType = { 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ - rapidxml_RapidXmlObject_methods, /* tp_methods */ - rapidxml_RapidXmlObject_members, /* tp_members */ + rapidxml_DocumentObject_methods, /* tp_methods */ + rapidxml_DocumentObject_members, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - reinterpret_cast(rapidxml_RapidXmlObject_init), /* tp_init */ + reinterpret_cast(rapidxml_DocumentObject_init), /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ 0, /* tp_free */ diff --git a/src/rapidxml_module.cpp b/src/rapidxml_module.cpp index 8f40fa8..88e4de2 100644 --- a/src/rapidxml_module.cpp +++ b/src/rapidxml_module.cpp @@ -52,8 +52,8 @@ PyMODINIT_FUNC initrapidxml(void) rapidxml_AttributeType.tp_base = &rapidxml_BaseType; if (PyType_Ready(&rapidxml_AttributeType) < 0) INITERROR; - rapidxml_RapidXmlType.tp_base = &rapidxml_NodeType; - if (PyType_Ready(&rapidxml_RapidXmlType) < 0) + rapidxml_DocumentType.tp_base = &rapidxml_NodeType; + if (PyType_Ready(&rapidxml_DocumentType) < 0) INITERROR; if (PyType_Ready(&rapidxml_NodeIteratorType) < 0) @@ -84,10 +84,10 @@ PyMODINIT_FUNC initrapidxml(void) "Attribute", reinterpret_cast(&rapidxml_AttributeType)); - Py_INCREF(&rapidxml_RapidXmlType); + Py_INCREF(&rapidxml_DocumentType); PyModule_AddObject(module, - "RapidXml", - reinterpret_cast(&rapidxml_RapidXmlType)); + "Document", + reinterpret_cast(&rapidxml_DocumentType)); Py_INCREF(&rapidxml_NodeIteratorType); PyModule_AddObject(module, From c8cee3766b68a86b2a30d8f3397548810c01932e Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Wed, 15 Apr 2015 07:12:37 +0900 Subject: [PATCH 021/101] attributes iterator --- README.md | 2 +- inc/common.h | 7 ++ setup.py | 1 + src/attributeiterator_object.cpp | 107 +++++++++++++++++++++++++++++++ src/node_object.cpp | 16 +++++ src/nodeiterator_object.cpp | 2 +- src/rapidxml_module.cpp | 7 ++ test/simple.py | 2 +- 8 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 src/attributeiterator_object.cpp diff --git a/README.md b/README.md index 2126ec3..f3c58f9 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Example import rapidxml - r = rapidxml.RapidXml("foo") # parsing from string + r = rapidxml.Document("foo") # parsing from string test = r.first_node("test") # get first node named test test.name = "foo" # changing node's name to foo r.first_node("test2").value = "bar" # changing node's value to bar diff --git a/inc/common.h b/inc/common.h index d5471f3..c6b0b3e 100644 --- a/inc/common.h +++ b/inc/common.h @@ -48,6 +48,12 @@ typedef struct { rapidxml::xml_node<>* node; } rapidxml_NodeIteratorObject; +typedef struct { + PyObject_HEAD + PyObject* parent; + rapidxml::xml_attribute<>* attribute; +} rapidxml_AttributeIteratorObject; + /* ** Types */ @@ -58,6 +64,7 @@ extern PyTypeObject rapidxml_AttributeType; extern PyTypeObject rapidxml_DocumentType; extern PyTypeObject rapidxml_NodeIteratorType; +extern PyTypeObject rapidxml_AttributeIteratorType; /* ** Exceptions diff --git a/setup.py b/setup.py index 54dbb36..bd1f4d2 100644 --- a/setup.py +++ b/setup.py @@ -20,6 +20,7 @@ "./src/attribute_object.cpp", "./src/document_object.cpp", "./src/nodeiterator_object.cpp", + "./src/attributeiterator_object.cpp", ], ) diff --git a/src/attributeiterator_object.cpp b/src/attributeiterator_object.cpp new file mode 100644 index 0000000..efa8097 --- /dev/null +++ b/src/attributeiterator_object.cpp @@ -0,0 +1,107 @@ +/* +** -*- coding: utf-8 -*- +** +** File: attributeiterator_object.cpp +** by Arzaroth Lekva +** arzaroth@arzaroth.com +** +*/ + +#include +#include +#include + +#include + +static void rapidxml_AttributeIteratorObject_dealloc(rapidxml_AttributeIteratorObject* self) { + Py_XDECREF(self->parent); + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} + +static PyObject* rapidxml_AttributeIteratorObject_new(PyTypeObject* type, + PyObject* args, + PyObject* kwds) { + rapidxml_AttributeIteratorObject* self; + + self = reinterpret_cast(type->tp_alloc(type, 0)); + if (self != NULL) { + self->attribute = NULL; + self->parent = NULL; + if (PyArg_ParseTuple(args, "O", &self->parent) && + self->parent != NULL) { + Py_INCREF(self->parent); + self->attribute = static_cast*> + (reinterpret_cast(self->parent) + ->base.underlying_obj)->first_attribute(); + } else { + Py_DECREF(self); + return NULL; + } + } + return reinterpret_cast(self); +} + +static PyObject* rapidxml_AttributeIteratorObject_iter(rapidxml_AttributeIteratorObject* self) { + Py_INCREF(self); + return reinterpret_cast(self); +} + +static PyObject* rapidxml_AttributeIteratorObject_iternext(rapidxml_AttributeIteratorObject* self) { + PyObject* res; + + if (self->attribute == NULL || self->parent == NULL) { + return NULL; + } + res = _bind_result(reinterpret_cast(self->parent), + self->attribute, &rapidxml_AttributeType); + self->attribute = self->attribute->next_attribute(); + return res; +} + +PyTypeObject rapidxml_AttributeIteratorType = { + PyVarObject_HEAD_INIT(NULL, 0) + "rapidxml.AttributeIterator", /* tp_name */ + sizeof(rapidxml_AttributeIteratorObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + reinterpret_cast(rapidxml_AttributeIteratorObject_dealloc), /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_repr */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /* tp_flags */ + "class for iterating over node's attributes", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + reinterpret_cast(rapidxml_AttributeIteratorObject_iter), /* tp_iter */ + reinterpret_cast(rapidxml_AttributeIteratorObject_iternext), /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + reinterpret_cast(rapidxml_AttributeIteratorObject_new), /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ +}; diff --git a/src/node_object.cpp b/src/node_object.cpp index d406096..d4d81bf 100644 --- a/src/node_object.cpp +++ b/src/node_object.cpp @@ -194,10 +194,26 @@ static PyObject* rapidxml_NodeObject_children(rapidxml_NodeObject* self, return reinterpret_cast(iterator); } +static PyObject* rapidxml_NodeObject_attributes(rapidxml_NodeObject* self, + void* closure) { + rapidxml_AttributeIteratorObject* iterator; + PyObject* args; + + args = Py_BuildValue("(O)", self); + iterator = reinterpret_cast + (PyObject_CallObject(reinterpret_cast(&rapidxml_AttributeIteratorType), + args)); + Py_DECREF(args); + return reinterpret_cast(iterator); +} + static PyGetSetDef rapidxml_NodeObject_getseters[] = { {"children", (getter)rapidxml_NodeObject_children, NULL, "return an NodeIteratorObject to iterate over a node's children"}, + {"attributes", + (getter)rapidxml_NodeObject_attributes, NULL, + "return an AttributeIteratorObject to iterate over a node's attributes"}, {NULL} }; diff --git a/src/nodeiterator_object.cpp b/src/nodeiterator_object.cpp index 802853b..db057b5 100644 --- a/src/nodeiterator_object.cpp +++ b/src/nodeiterator_object.cpp @@ -79,7 +79,7 @@ PyTypeObject rapidxml_NodeIteratorType = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /* tp_flags */ - "class for iterating over a Node object", /* tp_doc */ + "class for iterating over node's children", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ diff --git a/src/rapidxml_module.cpp b/src/rapidxml_module.cpp index 88e4de2..a5f2867 100644 --- a/src/rapidxml_module.cpp +++ b/src/rapidxml_module.cpp @@ -58,6 +58,8 @@ PyMODINIT_FUNC initrapidxml(void) if (PyType_Ready(&rapidxml_NodeIteratorType) < 0) INITERROR; + if (PyType_Ready(&rapidxml_AttributeIteratorType) < 0) + INITERROR; #if PY_MAJOR_VERSION >= 3 module = PyModule_Create(&moduledef); @@ -94,6 +96,11 @@ PyMODINIT_FUNC initrapidxml(void) "NodeIterator", reinterpret_cast(&rapidxml_NodeIteratorType)); + Py_INCREF(&rapidxml_AttributeIteratorType); + PyModule_AddObject(module, + "AttributeIterator", + reinterpret_cast(&rapidxml_AttributeIteratorType)); + rapidxml_RapidXmlError = PyErr_NewException("rapidxml.rapidxml_RapidXmlError", NULL, NULL); Py_INCREF(rapidxml_RapidXmlError); diff --git a/test/simple.py b/test/simple.py index 866878b..096e682 100755 --- a/test/simple.py +++ b/test/simple.py @@ -7,7 +7,7 @@ # import rapidxml -r = rapidxml.RapidXml("foo") # parsing from string +r = rapidxml.Document("foo") # parsing from string test = r.first_node("test") # get first node named test assert(test.name == "test") assert(test.value == "") From 663d0356205fa6511e2fc294712319bf96b95678 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Wed, 15 Apr 2015 07:46:21 +0900 Subject: [PATCH 022/101] base object comparison --- inc/common.h | 16 ++++++++++++++-- src/base_object.cpp | 26 +++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/inc/common.h b/inc/common.h index c6b0b3e..3afe354 100644 --- a/inc/common.h +++ b/inc/common.h @@ -10,12 +10,12 @@ #ifndef COMMON_H_ # define COMMON_H_ -# include - # if PY_MAJOR_VERSION >= 3 # define Py_TPFLAGS_HAVE_ITER 0 # endif +# include + /* ** Objects definitions */ @@ -79,4 +79,16 @@ extern PyObject* rapidxml_RapidXmlError; int _parse_args_for_name(PyObject*, PyObject*, const char**); PyObject* _bind_result(rapidxml_BaseObject*, rapidxml::xml_base<>*, PyTypeObject*); +/* +** Type check macros +*/ + +# define IS_DOC(o) (Py_TYPE(o) == &rapidxml_DocumentType) +# define IS_NODE(o) (IS_DOC(o) || (Py_TYPE(o) == &rapidxml_NodeType)) +# define IS_ATTR(o) (Py_TYPE(o) == &rapidxml_AttributeType) +# define IS_BASE(o) (IS_ATTR(o) || IS_NODE(o) || (Py_TYPE(o) == &rapidxml_BaseType)) + +# define IS_NODEITER(o) (Py_TYPE(o) == &rapidxml_NodeIteratorType) +# define IS_ATTRITER(o) (Py_TYPE(o) == &rapidxml_AttributeIteratorType) + #endif /* !COMMON_H_ */ diff --git a/src/base_object.cpp b/src/base_object.cpp index 8cf20d8..15c8f9a 100644 --- a/src/base_object.cpp +++ b/src/base_object.cpp @@ -36,6 +36,30 @@ static int rapidxml_BaseObject_init(rapidxml_BaseObject* self, return 0; } +static PyObject* rapidxml_BaseObject_richcmp(PyObject* obj1, + PyObject* obj2, + int op) { + PyObject* res; + bool c; + + if (!(IS_BASE(obj1) && IS_BASE(obj2))) { + PyErr_SetString(PyExc_TypeError, "Excepted instances of rapidxml.Base"); + return NULL; + } + switch (op) { + case Py_EQ: + c = (reinterpret_cast(obj1)->underlying_obj == + reinterpret_cast(obj2)->underlying_obj); + break; + default: + PyErr_SetNone(PyExc_NotImplementedError); + return NULL; + } + res = c ? Py_True : Py_False; + Py_INCREF(res); + return res; +} + static PyObject* rapidxml_BaseObject_getname(rapidxml_BaseObject* self, void* closure) { if (self->underlying_obj == NULL) { @@ -160,7 +184,7 @@ PyTypeObject rapidxml_BaseType = { "class representing a rapidxml::xml_base", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ - 0, /* tp_richcompare */ + reinterpret_cast(rapidxml_BaseObject_richcmp), /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ From 505af287cd8cec5311483498a7044d30a01c33bc Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Wed, 15 Apr 2015 09:28:50 +0900 Subject: [PATCH 023/101] typecheck for iterator, parse function --- src/attributeiterator_object.cpp | 2 +- src/document_object.cpp | 51 +++++++++++++++++++++++++------- src/nodeiterator_object.cpp | 2 +- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/attributeiterator_object.cpp b/src/attributeiterator_object.cpp index efa8097..d47333a 100644 --- a/src/attributeiterator_object.cpp +++ b/src/attributeiterator_object.cpp @@ -28,7 +28,7 @@ static PyObject* rapidxml_AttributeIteratorObject_new(PyTypeObject* type, self->attribute = NULL; self->parent = NULL; if (PyArg_ParseTuple(args, "O", &self->parent) && - self->parent != NULL) { + self->parent != NULL && IS_NODE(self->parent)) { Py_INCREF(self->parent); self->attribute = static_cast*> (reinterpret_cast(self->parent) diff --git a/src/document_object.cpp b/src/document_object.cpp index 533d8ce..841fc5a 100644 --- a/src/document_object.cpp +++ b/src/document_object.cpp @@ -23,23 +23,21 @@ static void rapidxml_DocumentObject_dealloc(rapidxml_DocumentObject* self) { Py_TYPE(self)->tp_free(reinterpret_cast(self)); } -static int rapidxml_DocumentObject_init(rapidxml_DocumentObject* self, - PyObject* args, - PyObject* kwds) { - const char* text; +static PyObject* rapidxml_DocumentObject_parse(rapidxml_DocumentObject* self, + PyObject* args, + PyObject* kwds) { + const char* text = NULL; int from_file = 0; PyObject* from_file_obj = NULL; char kw_text[] = "text"; char kw_from_file[] = "from_file"; std::vector text_vector; + PyObject* res; - if (rapidxml_NodeType.tp_init(reinterpret_cast(self), args, kwds) < 0) { - return -1; - } static char* kwlist[] = {kw_text, kw_from_file, NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|O", kwlist, &text, &from_file_obj)) { - return -1; + goto fail; } if (from_file_obj) { from_file = PyObject_IsTrue(from_file_obj); @@ -49,7 +47,7 @@ static int rapidxml_DocumentObject_init(rapidxml_DocumentObject* self, std::ifstream f(text, std::ios::binary); if (f.fail()) { PyErr_SetString(rapidxml_RapidXmlError, strerror(errno)); - return -1; + goto fail; } text_vector = std::vector((std::istreambuf_iterator(f)), std::istreambuf_iterator()); @@ -57,15 +55,44 @@ static int rapidxml_DocumentObject_init(rapidxml_DocumentObject* self, text = &text_vector[0]; } try { - self->base.base.underlying_obj = new rapidxml::xml_document<>(); - self->base.base.document = static_cast*>(self->base.base.underlying_obj); + self->base.base.document->clear(); (self->base.base.document ->parse) (self->base.base.document->allocate_string(text)); } catch (rapidxml::parse_error &e) { PyErr_SetString(rapidxml_RapidXmlError, e.what()); + goto fail; + } + res = Py_True; + goto end; + fail: + res = Py_False; + end: + Py_INCREF(res); + return res; +} + +static int rapidxml_DocumentObject_init(rapidxml_DocumentObject* self, + PyObject* args, + PyObject* kwds) { + const char* text = NULL; + PyObject* from_file_obj = NULL; + char kw_text[] = "text"; + char kw_from_file[] = "from_file"; + + if (rapidxml_NodeType.tp_init(reinterpret_cast(self), args, kwds) < 0) { return -1; } + static char* kwlist[] = {kw_text, kw_from_file, NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sO", kwlist, + &text, &from_file_obj)) { + return -1; + } + self->base.base.underlying_obj = new rapidxml::xml_document<>(); + self->base.base.document = static_cast*>(self->base.base.underlying_obj); + if (text) { + rapidxml_DocumentObject_parse(self, args, kwds); + } return 0; } @@ -114,6 +141,8 @@ static PyMemberDef rapidxml_DocumentObject_members[] = { }; static PyMethodDef rapidxml_DocumentObject_methods[] = { + {"parse", reinterpret_cast(rapidxml_DocumentObject_parse), + METH_VARARGS | METH_KEYWORDS, "parse given xml string, optionally from a file a from_file argument is True"}, {"allocate_node", reinterpret_cast(rapidxml_DocumentObject_allocate_node), METH_VARARGS | METH_KEYWORDS, "allocates a new node from the pool, and optionally assigns name and value to it"}, {"allocate_attribute", reinterpret_cast(rapidxml_DocumentObject_allocate_attribute), diff --git a/src/nodeiterator_object.cpp b/src/nodeiterator_object.cpp index db057b5..9b4b0dd 100644 --- a/src/nodeiterator_object.cpp +++ b/src/nodeiterator_object.cpp @@ -28,7 +28,7 @@ static PyObject* rapidxml_NodeIteratorObject_new(PyTypeObject* type, self->node = NULL; self->parent = NULL; if (PyArg_ParseTuple(args, "O", &self->parent) && - self->parent != NULL) { + self->parent != NULL && IS_NODE(self->parent)) { Py_INCREF(self->parent); self->node = static_cast*> (reinterpret_cast(self->parent) From 13bb815c09c4208863ccc32a9777fffca08119d0 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Wed, 15 Apr 2015 09:46:09 +0900 Subject: [PATCH 024/101] allocate string for name & value --- src/document_object.cpp | 12 ++++++++++++ src/node_object.cpp | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/src/document_object.cpp b/src/document_object.cpp index 841fc5a..939dcb3 100644 --- a/src/document_object.cpp +++ b/src/document_object.cpp @@ -111,6 +111,12 @@ static PyObject* rapidxml_DocumentObject_allocate_node(rapidxml_DocumentObject* Py_INCREF(Py_None); return Py_None; } + if (name) { + name = self->base.base.document->allocate_string(name); + } + if (value) { + value = self->base.base.document->allocate_string(value); + } node = self->base.base.document->allocate_node(rapidxml::node_element, name, value); return _bind_result(reinterpret_cast(self), node, &rapidxml_NodeType); @@ -131,6 +137,12 @@ static PyObject* rapidxml_DocumentObject_allocate_attribute(rapidxml_DocumentObj Py_INCREF(Py_None); return Py_None; } + if (name) { + name = self->base.base.document->allocate_string(name); + } + if (value) { + value = self->base.base.document->allocate_string(value); + } attribute = self->base.base.document->allocate_attribute(name, value); return _bind_result(reinterpret_cast(self), attribute, &rapidxml_AttributeType); diff --git a/src/node_object.cpp b/src/node_object.cpp index d4d81bf..f31c2ed 100644 --- a/src/node_object.cpp +++ b/src/node_object.cpp @@ -161,6 +161,13 @@ static PyObject* rapidxml_NodeObject_unparse(rapidxml_NodeObject* self, return Py_BuildValue("s", xml.c_str()); } +static PyObject* rapidxml_NodeObject_prepend_node(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + Py_INCREF(Py_None); + return Py_None; +} + static PyObject* rapidxml_NodeObject___str__(rapidxml_NodeObject* self) { PyObject* args; PyObject* res; From 67119bfd169e01dff486eb6a503df6a6b72e4baf Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Wed, 15 Apr 2015 09:58:42 +0900 Subject: [PATCH 025/101] prepend and append node --- src/node_object.cpp | 51 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/src/node_object.cpp b/src/node_object.cpp index f31c2ed..fb45569 100644 --- a/src/node_object.cpp +++ b/src/node_object.cpp @@ -141,6 +141,46 @@ static PyObject* rapidxml_NodeObject_last_attribute(rapidxml_NodeObject* self, return Py_None; } +static PyObject* rapidxml_NodeObject_prepend_node(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + char kw_node[] = "node"; + PyObject* node = NULL; + + static char* kwlist[] = {kw_node, NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, + &node) || + !IS_NODE(node)) { + goto end; + } + static_cast*>(self->base.underlying_obj)->prepend_node + (static_cast*> + (reinterpret_cast(node)->base.underlying_obj)); + end: + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* rapidxml_NodeObject_append_node(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + char kw_node[] = "node"; + PyObject* node = NULL; + + static char* kwlist[] = {kw_node, NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, + &node) || + !IS_NODE(node)) { + goto end; + } + static_cast*>(self->base.underlying_obj)->append_node + (static_cast*> + (reinterpret_cast(node)->base.underlying_obj)); + end: + Py_INCREF(Py_None); + return Py_None; +} + static PyObject* rapidxml_NodeObject_unparse(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { @@ -161,13 +201,6 @@ static PyObject* rapidxml_NodeObject_unparse(rapidxml_NodeObject* self, return Py_BuildValue("s", xml.c_str()); } -static PyObject* rapidxml_NodeObject_prepend_node(rapidxml_NodeObject* self, - PyObject* args, - PyObject* kwds) { - Py_INCREF(Py_None); - return Py_None; -} - static PyObject* rapidxml_NodeObject___str__(rapidxml_NodeObject* self) { PyObject* args; PyObject* res; @@ -241,6 +274,10 @@ static PyMethodDef rapidxml_NodeObject_methods[] = { METH_VARARGS | METH_KEYWORDS, "gets first attribute of node, optionally matching node name"}, {"last_attribute", reinterpret_cast(rapidxml_NodeObject_last_attribute), METH_VARARGS | METH_KEYWORDS, "gets last attribute of node, optionally matching node name"}, + {"prepend_node", reinterpret_cast(rapidxml_NodeObject_prepend_node), + METH_VARARGS | METH_KEYWORDS, "prepends a new child node"}, + {"append_node", reinterpret_cast(rapidxml_NodeObject_append_node), + METH_VARARGS | METH_KEYWORDS, "appends a new child node"}, {"unparse", reinterpret_cast(rapidxml_NodeObject_unparse), METH_VARARGS | METH_KEYWORDS, "return xml string"}, {NULL} From 498795a5a9b92c555574436da1454f4ff5c94e62 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Wed, 15 Apr 2015 10:56:31 +0900 Subject: [PATCH 026/101] typo, remove nodes --- src/base_object.cpp | 2 +- src/document_object.cpp | 2 +- src/node_object.cpp | 102 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 96 insertions(+), 10 deletions(-) diff --git a/src/base_object.cpp b/src/base_object.cpp index 15c8f9a..198eb1a 100644 --- a/src/base_object.cpp +++ b/src/base_object.cpp @@ -43,7 +43,7 @@ static PyObject* rapidxml_BaseObject_richcmp(PyObject* obj1, bool c; if (!(IS_BASE(obj1) && IS_BASE(obj2))) { - PyErr_SetString(PyExc_TypeError, "Excepted instances of rapidxml.Base"); + PyErr_SetString(PyExc_TypeError, "Expected instances of rapidxml.Base"); return NULL; } switch (op) { diff --git a/src/document_object.cpp b/src/document_object.cpp index 939dcb3..737f956 100644 --- a/src/document_object.cpp +++ b/src/document_object.cpp @@ -182,7 +182,7 @@ PyTypeObject rapidxml_DocumentType = { 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /*tp_flags*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ "class representing a rapidxml::xml_document", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ diff --git a/src/node_object.cpp b/src/node_object.cpp index fb45569..a26d388 100644 --- a/src/node_object.cpp +++ b/src/node_object.cpp @@ -149,14 +149,16 @@ static PyObject* rapidxml_NodeObject_prepend_node(rapidxml_NodeObject* self, static char* kwlist[] = {kw_node, NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, - &node) || - !IS_NODE(node)) { - goto end; + &node)) { + return NULL; + } + if (!IS_NODE(node)) { + PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml.Node"); + return NULL; } static_cast*>(self->base.underlying_obj)->prepend_node (static_cast*> (reinterpret_cast(node)->base.underlying_obj)); - end: Py_INCREF(Py_None); return Py_None; } @@ -169,14 +171,88 @@ static PyObject* rapidxml_NodeObject_append_node(rapidxml_NodeObject* self, static char* kwlist[] = {kw_node, NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, - &node) || - !IS_NODE(node)) { - goto end; + &node)) { + return NULL; + } + if (!IS_NODE(node)) { + PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml.Node"); + return NULL; } static_cast*>(self->base.underlying_obj)->append_node (static_cast*> (reinterpret_cast(node)->base.underlying_obj)); - end: + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* rapidxml_NodeObject_insert_node(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + char kw_where[] = "where"; + char kw_node[] = "node"; + PyObject* where = NULL; + PyObject* node = NULL; + + static char* kwlist[] = {kw_where, kw_node, NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, + &where, &node)) { + return NULL; + } + if (!(IS_NODE(where) && IS_NODE(node))) { + PyErr_SetString(PyExc_TypeError, "Expected instances of rapidxml.Node"); + return NULL; + } + static_cast*>(self->base.underlying_obj)->insert_node + (static_cast*> + (reinterpret_cast(where)->base.underlying_obj), + static_cast*> + (reinterpret_cast(node)->base.underlying_obj)); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* rapidxml_NodeObject_remove_first_node(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + static_cast*>(self->base.underlying_obj)->remove_first_node(); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* rapidxml_NodeObject_remove_last_node(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + static_cast*>(self->base.underlying_obj)->remove_last_node(); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* rapidxml_NodeObject_remove_node(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + char kw_node[] = "node"; + PyObject* node = NULL; + + static char* kwlist[] = {kw_node, NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, + &node)) { + return NULL; + } + if (!IS_NODE(node)) { + PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml.Node"); + return NULL; + } + static_cast*>(self->base.underlying_obj)->remove_node + (static_cast*> + (reinterpret_cast(node)->base.underlying_obj)); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* rapidxml_NodeObject_remove_all_nodes(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + static_cast*>(self->base.underlying_obj)->remove_all_nodes(); Py_INCREF(Py_None); return Py_None; } @@ -278,6 +354,16 @@ static PyMethodDef rapidxml_NodeObject_methods[] = { METH_VARARGS | METH_KEYWORDS, "prepends a new child node"}, {"append_node", reinterpret_cast(rapidxml_NodeObject_append_node), METH_VARARGS | METH_KEYWORDS, "appends a new child node"}, + {"insert_node", reinterpret_cast(rapidxml_NodeObject_insert_node), + METH_VARARGS | METH_KEYWORDS, "inserts a new child node at specified place"}, + {"remove_first_node", reinterpret_cast(rapidxml_NodeObject_remove_first_node), + METH_VARARGS | METH_KEYWORDS, "removes first child node"}, + {"remove_last_node", reinterpret_cast(rapidxml_NodeObject_remove_last_node), + METH_VARARGS | METH_KEYWORDS, "removes last child of the node"}, + {"remove_node", reinterpret_cast(rapidxml_NodeObject_remove_node), + METH_VARARGS | METH_KEYWORDS, "removes specified child from the node"}, + {"remove_all_nodes", reinterpret_cast(rapidxml_NodeObject_remove_all_nodes), + METH_VARARGS | METH_KEYWORDS, "removes all child nodes"}, {"unparse", reinterpret_cast(rapidxml_NodeObject_unparse), METH_VARARGS | METH_KEYWORDS, "return xml string"}, {NULL} From 6fcc915597416f4d15383af4555e42b20481c340 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Thu, 16 Apr 2015 08:00:27 +0900 Subject: [PATCH 027/101] add attributes --- src/node_object.cpp | 48 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/node_object.cpp b/src/node_object.cpp index a26d388..65e8fea 100644 --- a/src/node_object.cpp +++ b/src/node_object.cpp @@ -257,6 +257,50 @@ static PyObject* rapidxml_NodeObject_remove_all_nodes(rapidxml_NodeObject* self, return Py_None; } +static PyObject* rapidxml_NodeObject_prepend_attribute(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + char kw_attribute[] = "attribute"; + PyObject* attribute = NULL; + + static char* kwlist[] = {kw_attribute, NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, + &attribute)) { + return NULL; + } + if (!IS_ATTR(attribute)) { + PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml.Attribute"); + return NULL; + } + static_cast*>(self->base.underlying_obj)->prepend_attribute + (static_cast*> + (reinterpret_cast(attribute)->base.underlying_obj)); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* rapidxml_NodeObject_append_attribute(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + char kw_attribute[] = "attribute"; + PyObject* attribute = NULL; + + static char* kwlist[] = {kw_attribute, NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, + &attribute)) { + return NULL; + } + if (!IS_ATTR(attribute)) { + PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml.Attribute"); + return NULL; + } + static_cast*>(self->base.underlying_obj)->append_attribute + (static_cast*> + (reinterpret_cast(attribute)->base.underlying_obj)); + Py_INCREF(Py_None); + return Py_None; +} + static PyObject* rapidxml_NodeObject_unparse(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { @@ -364,6 +408,10 @@ static PyMethodDef rapidxml_NodeObject_methods[] = { METH_VARARGS | METH_KEYWORDS, "removes specified child from the node"}, {"remove_all_nodes", reinterpret_cast(rapidxml_NodeObject_remove_all_nodes), METH_VARARGS | METH_KEYWORDS, "removes all child nodes"}, + {"prepend_attribute", reinterpret_cast(rapidxml_NodeObject_prepend_attribute), + METH_VARARGS | METH_KEYWORDS, "prepends a new attribute to the node"}, + {"append_attribute", reinterpret_cast(rapidxml_NodeObject_append_attribute), + METH_VARARGS | METH_KEYWORDS, "appends a new attribute to the node"}, {"unparse", reinterpret_cast(rapidxml_NodeObject_unparse), METH_VARARGS | METH_KEYWORDS, "return xml string"}, {NULL} From e8d3e5141f5f138c583d073d213d9a5d4bcf176b Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Thu, 16 Apr 2015 08:53:18 +0900 Subject: [PATCH 028/101] sanity checks and finalizing api --- src/node_object.cpp | 103 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 98 insertions(+), 5 deletions(-) diff --git a/src/node_object.cpp b/src/node_object.cpp index 65e8fea..ce6465f 100644 --- a/src/node_object.cpp +++ b/src/node_object.cpp @@ -47,7 +47,8 @@ static PyObject* rapidxml_NodeObject_last_node(rapidxml_NodeObject* self, const char* name = NULL; rapidxml::xml_node<>* node; - if (!_parse_args_for_name(args, kwds, &name)) { + if (!(_parse_args_for_name(args, kwds, &name) && + static_cast*>(self->base.underlying_obj)->first_node())) { goto err; } node = static_cast*>(self->base.underlying_obj)->last_node(name); @@ -67,7 +68,8 @@ static PyObject* rapidxml_NodeObject_previous_sibling(rapidxml_NodeObject* self, const char* name = NULL; rapidxml::xml_node<>* node; - if (!_parse_args_for_name(args, kwds, &name)) { + if (!(_parse_args_for_name(args, kwds, &name) && + static_cast*>(self->base.underlying_obj)->parent())) { goto err; } node = static_cast*>(self->base.underlying_obj)->previous_sibling(name); @@ -87,7 +89,8 @@ static PyObject* rapidxml_NodeObject_next_sibling(rapidxml_NodeObject* self, const char* name = NULL; rapidxml::xml_node<>* node; - if (!_parse_args_for_name(args, kwds, &name)) { + if (!(_parse_args_for_name(args, kwds, &name) && + static_cast*>(self->base.underlying_obj)->parent())) { goto err; } node = static_cast*>(self->base.underlying_obj)->next_sibling(name); @@ -214,7 +217,9 @@ static PyObject* rapidxml_NodeObject_insert_node(rapidxml_NodeObject* self, static PyObject* rapidxml_NodeObject_remove_first_node(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { - static_cast*>(self->base.underlying_obj)->remove_first_node(); + if (static_cast*>(self->base.underlying_obj)->first_node()) { + static_cast*>(self->base.underlying_obj)->remove_first_node(); + } Py_INCREF(Py_None); return Py_None; } @@ -222,7 +227,9 @@ static PyObject* rapidxml_NodeObject_remove_first_node(rapidxml_NodeObject* self static PyObject* rapidxml_NodeObject_remove_last_node(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { - static_cast*>(self->base.underlying_obj)->remove_last_node(); + if (static_cast*>(self->base.underlying_obj)->first_node()) { + static_cast*>(self->base.underlying_obj)->remove_last_node(); + } Py_INCREF(Py_None); return Py_None; } @@ -301,6 +308,82 @@ static PyObject* rapidxml_NodeObject_append_attribute(rapidxml_NodeObject* self, return Py_None; } +static PyObject* rapidxml_NodeObject_insert_attribute(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + char kw_where[] = "where"; + char kw_attribute[] = "attribute"; + PyObject* where = NULL; + PyObject* attribute = NULL; + + static char* kwlist[] = {kw_where, kw_attribute, NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, + &where, &attribute)) { + return NULL; + } + if (!(IS_ATTR(where) && IS_ATTR(attribute))) { + PyErr_SetString(PyExc_TypeError, "Expected instances of rapidxml.Attribute"); + return NULL; + } + static_cast*>(self->base.underlying_obj)->insert_attribute + (static_cast*> + (reinterpret_cast(where)->base.underlying_obj), + static_cast*> + (reinterpret_cast(attribute)->base.underlying_obj)); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* rapidxml_NodeObject_remove_first_attribute(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + if (static_cast*>(self->base.underlying_obj)->first_attribute()) { + static_cast*>(self->base.underlying_obj)->remove_first_attribute(); + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* rapidxml_NodeObject_remove_last_attribute(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + if (static_cast*>(self->base.underlying_obj)->first_attribute()) { + static_cast*>(self->base.underlying_obj)->remove_last_attribute(); + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* rapidxml_NodeObject_remove_attribute(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + char kw_attribute[] = "attribute"; + PyObject* attribute = NULL; + + static char* kwlist[] = {kw_attribute, NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, + &attribute)) { + return NULL; + } + if (!IS_ATTR(attribute)) { + PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml.Attribute"); + return NULL; + } + static_cast*>(self->base.underlying_obj)->remove_attribute + (static_cast*> + (reinterpret_cast(attribute)->base.underlying_obj)); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* rapidxml_NodeObject_remove_all_attributes(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + static_cast*>(self->base.underlying_obj)->remove_all_attributes(); + Py_INCREF(Py_None); + return Py_None; +} + static PyObject* rapidxml_NodeObject_unparse(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { @@ -412,6 +495,16 @@ static PyMethodDef rapidxml_NodeObject_methods[] = { METH_VARARGS | METH_KEYWORDS, "prepends a new attribute to the node"}, {"append_attribute", reinterpret_cast(rapidxml_NodeObject_append_attribute), METH_VARARGS | METH_KEYWORDS, "appends a new attribute to the node"}, + {"insert_attribute", reinterpret_cast(rapidxml_NodeObject_insert_attribute), + METH_VARARGS | METH_KEYWORDS, "inserts a new attribute to the node at specified place"}, + {"remove_first_attribute", reinterpret_cast(rapidxml_NodeObject_remove_first_attribute), + METH_VARARGS | METH_KEYWORDS, "removes first attribute of the node"}, + {"remove_last_attribute", reinterpret_cast(rapidxml_NodeObject_remove_last_attribute), + METH_VARARGS | METH_KEYWORDS, "removes last attribute of the node"}, + {"remove_attribute", reinterpret_cast(rapidxml_NodeObject_remove_attribute), + METH_VARARGS | METH_KEYWORDS, "removes specified attribute from the node"}, + {"remove_all_attributes", reinterpret_cast(rapidxml_NodeObject_remove_all_attributes), + METH_VARARGS | METH_KEYWORDS, "removes all attributes of the node"}, {"unparse", reinterpret_cast(rapidxml_NodeObject_unparse), METH_VARARGS | METH_KEYWORDS, "return xml string"}, {NULL} From 6008c4426398967eca5ed2c9252f12b1c8e10e80 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Thu, 16 Apr 2015 09:49:06 +0900 Subject: [PATCH 029/101] reorganisation of module --- rapidxml/__init__.py | 13 +++++++++ {inc => rapidxml/c_ext/inc}/common.h | 0 .../c_ext/inc/rapidxml-1.13}/license.txt | 0 .../c_ext/inc/rapidxml-1.13}/rapidxml.hpp | 0 .../inc/rapidxml-1.13}/rapidxml_iterators.hpp | 0 .../inc/rapidxml-1.13}/rapidxml_print.hpp | 0 .../inc/rapidxml-1.13}/rapidxml_utils.hpp | 0 .../c_ext/src}/attribute_object.cpp | 2 +- .../c_ext/src}/attributeiterator_object.cpp | 2 +- {src => rapidxml/c_ext/src}/base_object.cpp | 4 +-- {src => rapidxml/c_ext/src}/common.cpp | 0 .../c_ext/src}/document_object.cpp | 2 +- {src => rapidxml/c_ext/src}/node_object.cpp | 18 ++++++------- .../c_ext/src}/nodeiterator_object.cpp | 2 +- .../c_ext/src}/rapidxml_module.cpp | 14 +++++----- rapidxml/rapidxml.py | 12 +++++++++ setup.py | 27 +++++++++++-------- 17 files changed, 63 insertions(+), 33 deletions(-) create mode 100644 rapidxml/__init__.py rename {inc => rapidxml/c_ext/inc}/common.h (100%) rename {rapidxml-1.13 => rapidxml/c_ext/inc/rapidxml-1.13}/license.txt (100%) rename {rapidxml-1.13 => rapidxml/c_ext/inc/rapidxml-1.13}/rapidxml.hpp (100%) rename {rapidxml-1.13 => rapidxml/c_ext/inc/rapidxml-1.13}/rapidxml_iterators.hpp (100%) rename {rapidxml-1.13 => rapidxml/c_ext/inc/rapidxml-1.13}/rapidxml_print.hpp (100%) rename {rapidxml-1.13 => rapidxml/c_ext/inc/rapidxml-1.13}/rapidxml_utils.hpp (100%) rename {src => rapidxml/c_ext/src}/attribute_object.cpp (98%) rename {src => rapidxml/c_ext/src}/attributeiterator_object.cpp (98%) rename {src => rapidxml/c_ext/src}/base_object.cpp (98%) rename {src => rapidxml/c_ext/src}/common.cpp (100%) rename {src => rapidxml/c_ext/src}/document_object.cpp (99%) rename {src => rapidxml/c_ext/src}/node_object.cpp (98%) rename {src => rapidxml/c_ext/src}/nodeiterator_object.cpp (98%) rename {src => rapidxml/c_ext/src}/rapidxml_module.cpp (88%) create mode 100644 rapidxml/rapidxml.py diff --git a/rapidxml/__init__.py b/rapidxml/__init__.py new file mode 100644 index 0000000..6fee501 --- /dev/null +++ b/rapidxml/__init__.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# File: __init__.py +# by Arzaroth Lekva +# arzaroth@arzaroth.com +# + +from .rapidxml import RapidXml + +__all__ = [ + 'RapidXml', + ] diff --git a/inc/common.h b/rapidxml/c_ext/inc/common.h similarity index 100% rename from inc/common.h rename to rapidxml/c_ext/inc/common.h diff --git a/rapidxml-1.13/license.txt b/rapidxml/c_ext/inc/rapidxml-1.13/license.txt similarity index 100% rename from rapidxml-1.13/license.txt rename to rapidxml/c_ext/inc/rapidxml-1.13/license.txt diff --git a/rapidxml-1.13/rapidxml.hpp b/rapidxml/c_ext/inc/rapidxml-1.13/rapidxml.hpp similarity index 100% rename from rapidxml-1.13/rapidxml.hpp rename to rapidxml/c_ext/inc/rapidxml-1.13/rapidxml.hpp diff --git a/rapidxml-1.13/rapidxml_iterators.hpp b/rapidxml/c_ext/inc/rapidxml-1.13/rapidxml_iterators.hpp similarity index 100% rename from rapidxml-1.13/rapidxml_iterators.hpp rename to rapidxml/c_ext/inc/rapidxml-1.13/rapidxml_iterators.hpp diff --git a/rapidxml-1.13/rapidxml_print.hpp b/rapidxml/c_ext/inc/rapidxml-1.13/rapidxml_print.hpp similarity index 100% rename from rapidxml-1.13/rapidxml_print.hpp rename to rapidxml/c_ext/inc/rapidxml-1.13/rapidxml_print.hpp diff --git a/rapidxml-1.13/rapidxml_utils.hpp b/rapidxml/c_ext/inc/rapidxml-1.13/rapidxml_utils.hpp similarity index 100% rename from rapidxml-1.13/rapidxml_utils.hpp rename to rapidxml/c_ext/inc/rapidxml-1.13/rapidxml_utils.hpp diff --git a/src/attribute_object.cpp b/rapidxml/c_ext/src/attribute_object.cpp similarity index 98% rename from src/attribute_object.cpp rename to rapidxml/c_ext/src/attribute_object.cpp index ffd856e..59ef131 100644 --- a/src/attribute_object.cpp +++ b/rapidxml/c_ext/src/attribute_object.cpp @@ -74,7 +74,7 @@ static PyMethodDef rapidxml_AttributeObject_methods[] = { PyTypeObject rapidxml_AttributeType = { PyVarObject_HEAD_INIT(NULL, 0) - "rapidxml.Attribute", /* tp_name */ + "rapidxml._rapidxml.Attribute", /* tp_name */ sizeof(rapidxml_AttributeObject), /* tp_basicsize */ 0, /* tp_itemsize */ 0, /* tp_dealloc */ diff --git a/src/attributeiterator_object.cpp b/rapidxml/c_ext/src/attributeiterator_object.cpp similarity index 98% rename from src/attributeiterator_object.cpp rename to rapidxml/c_ext/src/attributeiterator_object.cpp index d47333a..7d4b2da 100644 --- a/src/attributeiterator_object.cpp +++ b/rapidxml/c_ext/src/attributeiterator_object.cpp @@ -60,7 +60,7 @@ static PyObject* rapidxml_AttributeIteratorObject_iternext(rapidxml_AttributeIte PyTypeObject rapidxml_AttributeIteratorType = { PyVarObject_HEAD_INIT(NULL, 0) - "rapidxml.AttributeIterator", /* tp_name */ + "rapidxml._rapidxml.AttributeIterator", /* tp_name */ sizeof(rapidxml_AttributeIteratorObject), /* tp_basicsize */ 0, /* tp_itemsize */ reinterpret_cast(rapidxml_AttributeIteratorObject_dealloc), /* tp_dealloc */ diff --git a/src/base_object.cpp b/rapidxml/c_ext/src/base_object.cpp similarity index 98% rename from src/base_object.cpp rename to rapidxml/c_ext/src/base_object.cpp index 198eb1a..841f694 100644 --- a/src/base_object.cpp +++ b/rapidxml/c_ext/src/base_object.cpp @@ -43,7 +43,7 @@ static PyObject* rapidxml_BaseObject_richcmp(PyObject* obj1, bool c; if (!(IS_BASE(obj1) && IS_BASE(obj2))) { - PyErr_SetString(PyExc_TypeError, "Expected instances of rapidxml.Base"); + PyErr_SetString(PyExc_TypeError, "Expected instances of rapidxml._rapidxml.Base"); return NULL; } switch (op) { @@ -162,7 +162,7 @@ static PyMethodDef rapidxml_BaseObject_methods[] = { PyTypeObject rapidxml_BaseType = { PyVarObject_HEAD_INIT(NULL, 0) - "rapidxml.Base", /* tp_name */ + "rapidxml._rapidxml.Base", /* tp_name */ sizeof(rapidxml_BaseObject), /* tp_basicsize */ 0, /* tp_itemsize */ reinterpret_cast(rapidxml_BaseObject_dealloc), /* tp_dealloc */ diff --git a/src/common.cpp b/rapidxml/c_ext/src/common.cpp similarity index 100% rename from src/common.cpp rename to rapidxml/c_ext/src/common.cpp diff --git a/src/document_object.cpp b/rapidxml/c_ext/src/document_object.cpp similarity index 99% rename from src/document_object.cpp rename to rapidxml/c_ext/src/document_object.cpp index 737f956..e7b50e2 100644 --- a/src/document_object.cpp +++ b/rapidxml/c_ext/src/document_object.cpp @@ -164,7 +164,7 @@ static PyMethodDef rapidxml_DocumentObject_methods[] = { PyTypeObject rapidxml_DocumentType = { PyVarObject_HEAD_INIT(NULL, 0) - "rapidxml.Document", /* tp_name */ + "rapidxml._rapidxml.Document", /* tp_name */ sizeof(rapidxml_DocumentObject), /* tp_basicsize */ 0, /* tp_itemsize */ reinterpret_cast(rapidxml_DocumentObject_dealloc), /* tp_dealloc */ diff --git a/src/node_object.cpp b/rapidxml/c_ext/src/node_object.cpp similarity index 98% rename from src/node_object.cpp rename to rapidxml/c_ext/src/node_object.cpp index ce6465f..3f47042 100644 --- a/src/node_object.cpp +++ b/rapidxml/c_ext/src/node_object.cpp @@ -156,7 +156,7 @@ static PyObject* rapidxml_NodeObject_prepend_node(rapidxml_NodeObject* self, return NULL; } if (!IS_NODE(node)) { - PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml.Node"); + PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml._rapidxml.Node"); return NULL; } static_cast*>(self->base.underlying_obj)->prepend_node @@ -178,7 +178,7 @@ static PyObject* rapidxml_NodeObject_append_node(rapidxml_NodeObject* self, return NULL; } if (!IS_NODE(node)) { - PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml.Node"); + PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml._rapidxml.Node"); return NULL; } static_cast*>(self->base.underlying_obj)->append_node @@ -202,7 +202,7 @@ static PyObject* rapidxml_NodeObject_insert_node(rapidxml_NodeObject* self, return NULL; } if (!(IS_NODE(where) && IS_NODE(node))) { - PyErr_SetString(PyExc_TypeError, "Expected instances of rapidxml.Node"); + PyErr_SetString(PyExc_TypeError, "Expected instances of rapidxml._rapidxml.Node"); return NULL; } static_cast*>(self->base.underlying_obj)->insert_node @@ -246,7 +246,7 @@ static PyObject* rapidxml_NodeObject_remove_node(rapidxml_NodeObject* self, return NULL; } if (!IS_NODE(node)) { - PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml.Node"); + PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml._rapidxml.Node"); return NULL; } static_cast*>(self->base.underlying_obj)->remove_node @@ -276,7 +276,7 @@ static PyObject* rapidxml_NodeObject_prepend_attribute(rapidxml_NodeObject* self return NULL; } if (!IS_ATTR(attribute)) { - PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml.Attribute"); + PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml._rapidxml.Attribute"); return NULL; } static_cast*>(self->base.underlying_obj)->prepend_attribute @@ -298,7 +298,7 @@ static PyObject* rapidxml_NodeObject_append_attribute(rapidxml_NodeObject* self, return NULL; } if (!IS_ATTR(attribute)) { - PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml.Attribute"); + PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml._rapidxml.Attribute"); return NULL; } static_cast*>(self->base.underlying_obj)->append_attribute @@ -322,7 +322,7 @@ static PyObject* rapidxml_NodeObject_insert_attribute(rapidxml_NodeObject* self, return NULL; } if (!(IS_ATTR(where) && IS_ATTR(attribute))) { - PyErr_SetString(PyExc_TypeError, "Expected instances of rapidxml.Attribute"); + PyErr_SetString(PyExc_TypeError, "Expected instances of rapidxml._rapidxml.Attribute"); return NULL; } static_cast*>(self->base.underlying_obj)->insert_attribute @@ -366,7 +366,7 @@ static PyObject* rapidxml_NodeObject_remove_attribute(rapidxml_NodeObject* self, return NULL; } if (!IS_ATTR(attribute)) { - PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml.Attribute"); + PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml._rapidxml.Attribute"); return NULL; } static_cast*>(self->base.underlying_obj)->remove_attribute @@ -512,7 +512,7 @@ static PyMethodDef rapidxml_NodeObject_methods[] = { PyTypeObject rapidxml_NodeType = { PyVarObject_HEAD_INIT(NULL, 0) - "rapidxml.Node", /* tp_name */ + "rapidxml._rapidxml.Node", /* tp_name */ sizeof(rapidxml_NodeObject), /* tp_basicsize */ 0, /* tp_itemsize */ 0, /* tp_dealloc */ diff --git a/src/nodeiterator_object.cpp b/rapidxml/c_ext/src/nodeiterator_object.cpp similarity index 98% rename from src/nodeiterator_object.cpp rename to rapidxml/c_ext/src/nodeiterator_object.cpp index 9b4b0dd..09be49e 100644 --- a/src/nodeiterator_object.cpp +++ b/rapidxml/c_ext/src/nodeiterator_object.cpp @@ -60,7 +60,7 @@ static PyObject* rapidxml_NodeIteratorObject_iternext(rapidxml_NodeIteratorObjec PyTypeObject rapidxml_NodeIteratorType = { PyVarObject_HEAD_INIT(NULL, 0) - "rapidxml.NodeIterator", /* tp_name */ + "rapidxml._rapidxml.NodeIterator", /* tp_name */ sizeof(rapidxml_NodeIteratorObject), /* tp_basicsize */ 0, /* tp_itemsize */ reinterpret_cast(rapidxml_NodeIteratorObject_dealloc), /* tp_dealloc */ diff --git a/src/rapidxml_module.cpp b/rapidxml/c_ext/src/rapidxml_module.cpp similarity index 88% rename from src/rapidxml_module.cpp rename to rapidxml/c_ext/src/rapidxml_module.cpp index a5f2867..14599c6 100644 --- a/src/rapidxml_module.cpp +++ b/rapidxml/c_ext/src/rapidxml_module.cpp @@ -22,7 +22,7 @@ static PyMethodDef module_methods[] = { static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, - "rapidxml", + "rapidxml._rapidxml", "python module for rapidxml bindings", -1, module_methods, @@ -34,12 +34,12 @@ static struct PyModuleDef moduledef = { # define INITERROR return NULL -PyMODINIT_FUNC PyInit_rapidxml(void) +PyMODINIT_FUNC PyInit__rapidxml(void) #else # define INITERROR return -PyMODINIT_FUNC initrapidxml(void) +PyMODINIT_FUNC init_rapidxml(void) #endif { PyObject* module; @@ -64,7 +64,7 @@ PyMODINIT_FUNC initrapidxml(void) #if PY_MAJOR_VERSION >= 3 module = PyModule_Create(&moduledef); #else - module = Py_InitModule3("rapidxml", + module = Py_InitModule3("rapidxml._rapidxml", module_methods, "rapidxml module for rapidxml bindings"); #endif @@ -101,11 +101,11 @@ PyMODINIT_FUNC initrapidxml(void) "AttributeIterator", reinterpret_cast(&rapidxml_AttributeIteratorType)); - rapidxml_RapidXmlError = PyErr_NewException("rapidxml.rapidxml_RapidXmlError", - NULL, NULL); + rapidxml_RapidXmlError = PyErr_NewException("rapidxml._rapidxml.RapidXmlError", + NULL, NULL); Py_INCREF(rapidxml_RapidXmlError); PyModule_AddObject(module, - "rapidxml_RapidXmlError", + "RapidXmlError", rapidxml_RapidXmlError); #if PY_MAJOR_VERSION >= 3 diff --git a/rapidxml/rapidxml.py b/rapidxml/rapidxml.py new file mode 100644 index 0000000..ddb614f --- /dev/null +++ b/rapidxml/rapidxml.py @@ -0,0 +1,12 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# File: rapidxml.py +# by Arzaroth Lekva +# arzaroth@arzaroth.com +# + +import rapidxml._rapidxml + +class RapidXml(rapidxml._rapidxml.Document): + pass diff --git a/setup.py b/setup.py index bd1f4d2..843bfad 100644 --- a/setup.py +++ b/setup.py @@ -6,21 +6,24 @@ # arzaroth@arzaroth.com # -from setuptools import setup, Extension +from setuptools import setup, Extension, find_packages -rapidxml = Extension("rapidxml", +rapidxml = Extension("rapidxml._rapidxml", define_macros=[('MAJOR_VERSION', '1'), ('MINOR_VERSION', '0')], - include_dirs=['./rapidxml-1.13/', './inc/'], + include_dirs=[ + './rapidxml/c_ext/inc/', + './rapidxml/c_ext/inc/rapidxml-1.13/', + ], sources=[ - "./src/common.cpp", - "./src/rapidxml_module.cpp", - "./src/base_object.cpp", - "./src/node_object.cpp", - "./src/attribute_object.cpp", - "./src/document_object.cpp", - "./src/nodeiterator_object.cpp", - "./src/attributeiterator_object.cpp", + "./rapidxml/c_ext/src/common.cpp", + "./rapidxml/c_ext/src/rapidxml_module.cpp", + "./rapidxml/c_ext/src/base_object.cpp", + "./rapidxml/c_ext/src/node_object.cpp", + "./rapidxml/c_ext/src/attribute_object.cpp", + "./rapidxml/c_ext/src/document_object.cpp", + "./rapidxml/c_ext/src/nodeiterator_object.cpp", + "./rapidxml/c_ext/src/attributeiterator_object.cpp", ], ) @@ -35,4 +38,6 @@ description='python bindings for RapidXml, a C++ XML parsing library', keywords='rapidxml xml parsing', + + packages=['rapidxml'], ) From 9c372d029bc2d6ca1375fad0704b642748bb9926 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Thu, 16 Apr 2015 09:50:59 +0900 Subject: [PATCH 030/101] updated tests --- README.md | 2 +- test/simple.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f3c58f9..2126ec3 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Example import rapidxml - r = rapidxml.Document("foo") # parsing from string + r = rapidxml.RapidXml("foo") # parsing from string test = r.first_node("test") # get first node named test test.name = "foo" # changing node's name to foo r.first_node("test2").value = "bar" # changing node's value to bar diff --git a/test/simple.py b/test/simple.py index 096e682..866878b 100755 --- a/test/simple.py +++ b/test/simple.py @@ -7,7 +7,7 @@ # import rapidxml -r = rapidxml.Document("foo") # parsing from string +r = rapidxml.RapidXml("foo") # parsing from string test = r.first_node("test") # get first node named test assert(test.name == "test") assert(test.value == "") From cfff7b8af29a327f0fa7a26bc6ff330385624cdb Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Fri, 17 Apr 2015 08:08:47 +0900 Subject: [PATCH 031/101] copy and started python subclass --- rapidxml/c_ext/inc/common.h | 14 +++++----- rapidxml/c_ext/src/base_object.cpp | 23 ++++++++++++++++ rapidxml/rapidxml.py | 42 +++++++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 8 deletions(-) diff --git a/rapidxml/c_ext/inc/common.h b/rapidxml/c_ext/inc/common.h index 3afe354..a0eb39e 100644 --- a/rapidxml/c_ext/inc/common.h +++ b/rapidxml/c_ext/inc/common.h @@ -11,7 +11,7 @@ # define COMMON_H_ # if PY_MAJOR_VERSION >= 3 -# define Py_TPFLAGS_HAVE_ITER 0 +# define Py_TPFLAGS_HAVE_ITER (0) # endif # include @@ -83,12 +83,12 @@ PyObject* _bind_result(rapidxml_BaseObject*, rapidxml::xml_base<>*, PyTypeObject ** Type check macros */ -# define IS_DOC(o) (Py_TYPE(o) == &rapidxml_DocumentType) -# define IS_NODE(o) (IS_DOC(o) || (Py_TYPE(o) == &rapidxml_NodeType)) -# define IS_ATTR(o) (Py_TYPE(o) == &rapidxml_AttributeType) -# define IS_BASE(o) (IS_ATTR(o) || IS_NODE(o) || (Py_TYPE(o) == &rapidxml_BaseType)) +# define IS_DOC(o) ((o) && PyObject_TypeCheck(o, &rapidxml_DocumentType)) +# define IS_NODE(o) ((o) && PyObject_TypeCheck(o, &rapidxml_NodeType)) +# define IS_ATTR(o) ((o) && PyObject_TypeCheck(o, &rapidxml_AttributeType)) +# define IS_BASE(o) ((o) && PyObject_TypeCheck(o, &rapidxml_BaseType)) -# define IS_NODEITER(o) (Py_TYPE(o) == &rapidxml_NodeIteratorType) -# define IS_ATTRITER(o) (Py_TYPE(o) == &rapidxml_AttributeIteratorType) +# define IS_NODEITER(o) ((o) && PyObject_TypeCheck(o, &rapidxml_NodeIteratorType)) +# define IS_ATTRITER(o) ((o) && PyObject_TypeCheck(o, &rapidxml_AttributeIteratorType)) #endif /* !COMMON_H_ */ diff --git a/rapidxml/c_ext/src/base_object.cpp b/rapidxml/c_ext/src/base_object.cpp index 841f694..90ae255 100644 --- a/rapidxml/c_ext/src/base_object.cpp +++ b/rapidxml/c_ext/src/base_object.cpp @@ -36,6 +36,27 @@ static int rapidxml_BaseObject_init(rapidxml_BaseObject* self, return 0; } +static PyObject* rapidxml_BaseObject_copy(rapidxml_BaseObject* self, + PyObject* args, + PyObject* kwds) { + PyObject* other = NULL; + char kw_other[] = "other"; + + static char* kwlist[] = {kw_other, NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, + &other)) { + return NULL; + } + if (!IS_BASE(other)) { + PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml._rapidxml.Base"); + return NULL; + } + self->underlying_obj = reinterpret_cast(other)->underlying_obj; + self->document = reinterpret_cast(other)->document; + Py_INCREF(self); + return reinterpret_cast(self); +} + static PyObject* rapidxml_BaseObject_richcmp(PyObject* obj1, PyObject* obj2, int op) { @@ -157,6 +178,8 @@ static PyMemberDef rapidxml_BaseObject_members[] = { }; static PyMethodDef rapidxml_BaseObject_methods[] = { + {"copy", reinterpret_cast(rapidxml_BaseObject_copy), + METH_VARARGS | METH_KEYWORDS, "copy another Base object, returning current instance"}, {NULL} }; diff --git a/rapidxml/rapidxml.py b/rapidxml/rapidxml.py index ddb614f..08a5c74 100644 --- a/rapidxml/rapidxml.py +++ b/rapidxml/rapidxml.py @@ -8,5 +8,45 @@ import rapidxml._rapidxml -class RapidXml(rapidxml._rapidxml.Document): +class DictNode(rapidxml._rapidxml.Node): + def get_nodes(self, name): + node = self.first_node(name) + if node is None: + return None + res = [DictNode().copy(node)] + node = node.next_sibling(name) + if node is None: + return res[0] + while node is not None: + res.append(DictNode().copy(node)) + node = node.next_sibling(name) + return res + + def get_attributes(self, name): + attribute = self.first_attribute(name) + if attribute is None: + return None + res = [attribute] + attribute = attribute.next_attribute(name) + if attribute is None: + return res[0] + while attribute is not None: + res.append(attribute) + attribute = attribute.next_attribute(name) + return res + + def __getitem__(self, name): + res = None + if name.startswith('@'): + res = self.get_attributes(name[1:]) + else: + res = self.get_nodes(name) + if res is None: + raise KeyError(name) + return res + + def __setitem__(self, name, value): + raise NotImplementedError("WIP") + +class RapidXml(DictNode, rapidxml._rapidxml.Document): pass From 297aa34ec9656d8c7faaf067ba37e843fca55271 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Fri, 17 Apr 2015 10:21:34 +0900 Subject: [PATCH 032/101] clone node --- rapidxml/c_ext/src/node_object.cpp | 31 ++++++++++++++++++++++++------ rapidxml/rapidxml.py | 3 --- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/rapidxml/c_ext/src/node_object.cpp b/rapidxml/c_ext/src/node_object.cpp index 3f47042..d41cf8f 100644 --- a/rapidxml/c_ext/src/node_object.cpp +++ b/rapidxml/c_ext/src/node_object.cpp @@ -21,6 +21,23 @@ static int rapidxml_NodeObject_init(rapidxml_NodeObject* self, return rapidxml_BaseType.tp_init(reinterpret_cast(self), args, kwds); } +static PyObject* rapidxml_NodeObject_clone(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + rapidxml::xml_node<>* node; + + if (self->base.underlying_obj == NULL || + self->base.document == NULL) { + PyErr_SetString(rapidxml_RapidXmlError, + "underlying mechanism failed"); + return NULL; + } + node = self->base.document->clone_node + (static_cast*>(self->base.underlying_obj)); + return _bind_result(reinterpret_cast(self), + node, &rapidxml_NodeType); +} + static PyObject* rapidxml_NodeObject_first_node(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { @@ -465,6 +482,8 @@ static PyMemberDef rapidxml_NodeObject_members[] = { }; static PyMethodDef rapidxml_NodeObject_methods[] = { + {"clone", reinterpret_cast(rapidxml_NodeObject_clone), + METH_NOARGS, "clones the xml node and its hierachy"}, {"first_node", reinterpret_cast(rapidxml_NodeObject_first_node), METH_VARARGS | METH_KEYWORDS, "gets first child node, optionally matching node name"}, {"last_node", reinterpret_cast(rapidxml_NodeObject_last_node), @@ -484,13 +503,13 @@ static PyMethodDef rapidxml_NodeObject_methods[] = { {"insert_node", reinterpret_cast(rapidxml_NodeObject_insert_node), METH_VARARGS | METH_KEYWORDS, "inserts a new child node at specified place"}, {"remove_first_node", reinterpret_cast(rapidxml_NodeObject_remove_first_node), - METH_VARARGS | METH_KEYWORDS, "removes first child node"}, + METH_NOARGS, "removes first child node"}, {"remove_last_node", reinterpret_cast(rapidxml_NodeObject_remove_last_node), - METH_VARARGS | METH_KEYWORDS, "removes last child of the node"}, + METH_NOARGS, "removes last child of the node"}, {"remove_node", reinterpret_cast(rapidxml_NodeObject_remove_node), METH_VARARGS | METH_KEYWORDS, "removes specified child from the node"}, {"remove_all_nodes", reinterpret_cast(rapidxml_NodeObject_remove_all_nodes), - METH_VARARGS | METH_KEYWORDS, "removes all child nodes"}, + METH_NOARGS, "removes all child nodes"}, {"prepend_attribute", reinterpret_cast(rapidxml_NodeObject_prepend_attribute), METH_VARARGS | METH_KEYWORDS, "prepends a new attribute to the node"}, {"append_attribute", reinterpret_cast(rapidxml_NodeObject_append_attribute), @@ -498,13 +517,13 @@ static PyMethodDef rapidxml_NodeObject_methods[] = { {"insert_attribute", reinterpret_cast(rapidxml_NodeObject_insert_attribute), METH_VARARGS | METH_KEYWORDS, "inserts a new attribute to the node at specified place"}, {"remove_first_attribute", reinterpret_cast(rapidxml_NodeObject_remove_first_attribute), - METH_VARARGS | METH_KEYWORDS, "removes first attribute of the node"}, + METH_NOARGS, "removes first attribute of the node"}, {"remove_last_attribute", reinterpret_cast(rapidxml_NodeObject_remove_last_attribute), - METH_VARARGS | METH_KEYWORDS, "removes last attribute of the node"}, + METH_NOARGS, "removes last attribute of the node"}, {"remove_attribute", reinterpret_cast(rapidxml_NodeObject_remove_attribute), METH_VARARGS | METH_KEYWORDS, "removes specified attribute from the node"}, {"remove_all_attributes", reinterpret_cast(rapidxml_NodeObject_remove_all_attributes), - METH_VARARGS | METH_KEYWORDS, "removes all attributes of the node"}, + METH_NOARGS, "removes all attributes of the node"}, {"unparse", reinterpret_cast(rapidxml_NodeObject_unparse), METH_VARARGS | METH_KEYWORDS, "return xml string"}, {NULL} diff --git a/rapidxml/rapidxml.py b/rapidxml/rapidxml.py index 08a5c74..e1c7409 100644 --- a/rapidxml/rapidxml.py +++ b/rapidxml/rapidxml.py @@ -45,8 +45,5 @@ def __getitem__(self, name): raise KeyError(name) return res - def __setitem__(self, name, value): - raise NotImplementedError("WIP") - class RapidXml(DictNode, rapidxml._rapidxml.Document): pass From dfc5b105f7bc8b4ef14ac17b505fbe2fee4db39b Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Fri, 17 Apr 2015 12:29:31 +0900 Subject: [PATCH 033/101] semver --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 843bfad..c3890fd 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ setup( ext_modules=[rapidxml], name='RapidXml', - version='1.0', + version='v1.0.0-alpha', license='MIT', author='Marc-Etienne Barrut', From fdb2e691b167689bc380b03f259a1f3a7da3aaf2 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Fri, 17 Apr 2015 12:37:55 +0900 Subject: [PATCH 034/101] download url --- setup.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index c3890fd..6d62e96 100644 --- a/setup.py +++ b/setup.py @@ -6,11 +6,14 @@ # arzaroth@arzaroth.com # -from setuptools import setup, Extension, find_packages +import os +from setuptools import setup, Extension + +VERSION = ("1", "0", "0-alpha") rapidxml = Extension("rapidxml._rapidxml", - define_macros=[('MAJOR_VERSION', '1'), - ('MINOR_VERSION', '0')], + define_macros=[('MAJOR_VERSION', VERSION[0]), + ('MINOR_VERSION', VERSION[1])], include_dirs=[ './rapidxml/c_ext/inc/', './rapidxml/c_ext/inc/rapidxml-1.13/', @@ -30,13 +33,17 @@ setup( ext_modules=[rapidxml], name='RapidXml', - version='v1.0.0-alpha', + version='.'.join(VERSION), license='MIT', + url='https://github.com/Arzaroth/python_rapidxml', + download_url='https://github.com/Arzaroth/python_rapidxml/tarball/%s' % ('.'.join(VERSION)), + author='Marc-Etienne Barrut', author_email='lekva@arzaroth.com', description='python bindings for RapidXml, a C++ XML parsing library', + long_description=open(os.path.join(os.path.dirname(__file__), 'README.md')).read(), keywords='rapidxml xml parsing', packages=['rapidxml'], From 16a80a10e761444aa9b8a6ecc48d7c4d30c42d4e Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Fri, 17 Apr 2015 15:08:13 +0900 Subject: [PATCH 035/101] nothing to see here --- setup.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 6d62e96..9bd6d09 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,6 @@ # arzaroth@arzaroth.com # -import os from setuptools import setup, Extension VERSION = ("1", "0", "0-alpha") @@ -43,7 +42,7 @@ author_email='lekva@arzaroth.com', description='python bindings for RapidXml, a C++ XML parsing library', - long_description=open(os.path.join(os.path.dirname(__file__), 'README.md')).read(), + long_description=open('README.md').read(), keywords='rapidxml xml parsing', packages=['rapidxml'], From bc4c6a525765cfff08f6e6f5c95f6760de595f9f Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Fri, 17 Apr 2015 15:48:05 +0900 Subject: [PATCH 036/101] attribute_prefix and cdata_key --- rapidxml/c_ext/src/document_object.cpp | 2 +- rapidxml/rapidxml.py | 19 ++++++++++++++++--- setup.py | 2 +- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/rapidxml/c_ext/src/document_object.cpp b/rapidxml/c_ext/src/document_object.cpp index e7b50e2..57ab6ea 100644 --- a/rapidxml/c_ext/src/document_object.cpp +++ b/rapidxml/c_ext/src/document_object.cpp @@ -90,7 +90,7 @@ static int rapidxml_DocumentObject_init(rapidxml_DocumentObject* self, } self->base.base.underlying_obj = new rapidxml::xml_document<>(); self->base.base.document = static_cast*>(self->base.base.underlying_obj); - if (text) { + if (text && *text) { rapidxml_DocumentObject_parse(self, args, kwds); } return 0; diff --git a/rapidxml/rapidxml.py b/rapidxml/rapidxml.py index e1c7409..f99a1b5 100644 --- a/rapidxml/rapidxml.py +++ b/rapidxml/rapidxml.py @@ -9,6 +9,11 @@ import rapidxml._rapidxml class DictNode(rapidxml._rapidxml.Node): + def __init__(self, attribute_prefix='@', cdata_key='#text'): + rapidxml._rapidxml.Node.__init__(self) + self.attribute_prefix = attribute_prefix + self.cdata_key = cdata_key + def get_nodes(self, name): node = self.first_node(name) if node is None: @@ -37,8 +42,10 @@ def get_attributes(self, name): def __getitem__(self, name): res = None - if name.startswith('@'): - res = self.get_attributes(name[1:]) + if name == self.cdata_key: + res = self.value + elif name.startswith(self.attribute_prefix): + res = self.get_attributes(name[len(self.attribute_prefix):]) else: res = self.get_nodes(name) if res is None: @@ -46,4 +53,10 @@ def __getitem__(self, name): return res class RapidXml(DictNode, rapidxml._rapidxml.Document): - pass + def __init__(self, + text="", + from_file=False, + attribute_prefix='@', + cdata_key='#text'): + DictNode.__init__(self, attribute_prefix, cdata_key) + rapidxml._rapidxml.Document.__init__(self, text, from_file) diff --git a/setup.py b/setup.py index 9bd6d09..0a8a1fa 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ from setuptools import setup, Extension -VERSION = ("1", "0", "0-alpha") +VERSION = ("1", "0", "0-alpha.1") rapidxml = Extension("rapidxml._rapidxml", define_macros=[('MAJOR_VERSION', VERSION[0]), From 1784de05691178b94f4611590a787c4bc11346a0 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Fri, 17 Apr 2015 15:53:58 +0900 Subject: [PATCH 037/101] readme issue, try #1 --- README.md => README | 0 setup.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename README.md => README (100%) diff --git a/README.md b/README similarity index 100% rename from README.md rename to README diff --git a/setup.py b/setup.py index 0a8a1fa..604bb8f 100644 --- a/setup.py +++ b/setup.py @@ -42,7 +42,7 @@ author_email='lekva@arzaroth.com', description='python bindings for RapidXml, a C++ XML parsing library', - long_description=open('README.md').read(), + long_description=open('README').read(), keywords='rapidxml xml parsing', packages=['rapidxml'], From 4d4d2911c7d180f5870261e85b9aac56de2343ef Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Fri, 17 Apr 2015 15:55:47 +0900 Subject: [PATCH 038/101] version bump --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 604bb8f..47231a1 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ from setuptools import setup, Extension -VERSION = ("1", "0", "0-alpha.1") +VERSION = ("1", "0", "0-alpha.2") rapidxml = Extension("rapidxml._rapidxml", define_macros=[('MAJOR_VERSION', VERSION[0]), From 4f4f40b1d99562959ef36c5bdd75c92b0c5e0781 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Fri, 17 Apr 2015 16:22:20 +0900 Subject: [PATCH 039/101] using manifest --- MANIFEST.in | 5 +++++ setup.py | 18 +++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 MANIFEST.in diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..509a658 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,5 @@ +include ./setup.py + +recursive-include ./rapidxml/c_ext/inc *.h *.hpp + +prune ./test diff --git a/setup.py b/setup.py index 47231a1..63317d9 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ from setuptools import setup, Extension -VERSION = ("1", "0", "0-alpha.2") +VERSION = ("1", "0", "0-alpha.3") rapidxml = Extension("rapidxml._rapidxml", define_macros=[('MAJOR_VERSION', VERSION[0]), @@ -18,14 +18,14 @@ './rapidxml/c_ext/inc/rapidxml-1.13/', ], sources=[ - "./rapidxml/c_ext/src/common.cpp", - "./rapidxml/c_ext/src/rapidxml_module.cpp", - "./rapidxml/c_ext/src/base_object.cpp", - "./rapidxml/c_ext/src/node_object.cpp", - "./rapidxml/c_ext/src/attribute_object.cpp", - "./rapidxml/c_ext/src/document_object.cpp", - "./rapidxml/c_ext/src/nodeiterator_object.cpp", - "./rapidxml/c_ext/src/attributeiterator_object.cpp", + './rapidxml/c_ext/src/common.cpp', + './rapidxml/c_ext/src/rapidxml_module.cpp', + './rapidxml/c_ext/src/base_object.cpp', + './rapidxml/c_ext/src/node_object.cpp', + './rapidxml/c_ext/src/attribute_object.cpp', + './rapidxml/c_ext/src/document_object.cpp', + './rapidxml/c_ext/src/nodeiterator_object.cpp', + './rapidxml/c_ext/src/attributeiterator_object.cpp', ], ) From 7d976c3bbf3ad5c2df0d3df96a013fa3e0f05505 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Fri, 17 Apr 2015 16:24:38 +0900 Subject: [PATCH 040/101] manifest & setup --- MANIFEST.in | 6 +++--- setup.py | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index 509a658..54662c4 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,5 @@ -include ./setup.py +include setup.py -recursive-include ./rapidxml/c_ext/inc *.h *.hpp +recursive-include rapidxml/c_ext/inc *.h *.hpp -prune ./test +prune test diff --git a/setup.py b/setup.py index 63317d9..6b26a9e 100644 --- a/setup.py +++ b/setup.py @@ -14,18 +14,18 @@ define_macros=[('MAJOR_VERSION', VERSION[0]), ('MINOR_VERSION', VERSION[1])], include_dirs=[ - './rapidxml/c_ext/inc/', - './rapidxml/c_ext/inc/rapidxml-1.13/', + 'rapidxml/c_ext/inc/', + 'rapidxml/c_ext/inc/rapidxml-1.13/', ], sources=[ - './rapidxml/c_ext/src/common.cpp', - './rapidxml/c_ext/src/rapidxml_module.cpp', - './rapidxml/c_ext/src/base_object.cpp', - './rapidxml/c_ext/src/node_object.cpp', - './rapidxml/c_ext/src/attribute_object.cpp', - './rapidxml/c_ext/src/document_object.cpp', - './rapidxml/c_ext/src/nodeiterator_object.cpp', - './rapidxml/c_ext/src/attributeiterator_object.cpp', + 'rapidxml/c_ext/src/common.cpp', + 'rapidxml/c_ext/src/rapidxml_module.cpp', + 'rapidxml/c_ext/src/base_object.cpp', + 'rapidxml/c_ext/src/node_object.cpp', + 'rapidxml/c_ext/src/attribute_object.cpp', + 'rapidxml/c_ext/src/document_object.cpp', + 'rapidxml/c_ext/src/nodeiterator_object.cpp', + 'rapidxml/c_ext/src/attributeiterator_object.cpp', ], ) From 7f475edababdf36cfc03cb0a481787eb0a6a4e2f Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Sat, 18 Apr 2015 10:53:07 +0900 Subject: [PATCH 041/101] parent getter --- rapidxml/c_ext/src/base_object.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/rapidxml/c_ext/src/base_object.cpp b/rapidxml/c_ext/src/base_object.cpp index 90ae255..2d7b540 100644 --- a/rapidxml/c_ext/src/base_object.cpp +++ b/rapidxml/c_ext/src/base_object.cpp @@ -163,6 +163,23 @@ static int rapidxml_BaseObject_setvalue(rapidxml_BaseObject* self, return 0; } +static PyObject* rapidxml_BaseObject_getparent(rapidxml_BaseObject* self, + void* closure) { + rapidxml::xml_node<>* parent; + + if (self->underlying_obj == NULL || self->document == NULL) { + PyErr_SetString(rapidxml_RapidXmlError, + "underlying mechanism failed"); + return NULL; + } + parent = self->underlying_obj->parent(); + if (parent == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return _bind_result(self, parent, &rapidxml_NodeType); +} + static PyGetSetDef rapidxml_BaseObject_getseters[] = { {"name", (getter)rapidxml_BaseObject_getname, (setter)rapidxml_BaseObject_setname, @@ -170,6 +187,9 @@ static PyGetSetDef rapidxml_BaseObject_getseters[] = { {"value", (getter)rapidxml_BaseObject_getvalue, (setter)rapidxml_BaseObject_setvalue, "value of xml entity"}, + {"parent", + (getter)rapidxml_BaseObject_getparent, NULL, + "gets node parent"}, {NULL} }; From edb6fd0a1cef43a27f09ba65bf6a19adddbc6838 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Sat, 18 Apr 2015 10:56:10 +0900 Subject: [PATCH 042/101] passing correct parameters to child nodes --- rapidxml/rapidxml.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rapidxml/rapidxml.py b/rapidxml/rapidxml.py index f99a1b5..f71e772 100644 --- a/rapidxml/rapidxml.py +++ b/rapidxml/rapidxml.py @@ -18,12 +18,12 @@ def get_nodes(self, name): node = self.first_node(name) if node is None: return None - res = [DictNode().copy(node)] + res = [DictNode(self.attribute_prefix, self.cdata_key).copy(node)] node = node.next_sibling(name) if node is None: return res[0] while node is not None: - res.append(DictNode().copy(node)) + res.append(DictNode(self.attribute_prefix, self.cdata_key).copy(node)) node = node.next_sibling(name) return res From 78ef0cc228125b3f00b7c9b5c521aa9c9fa68271 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Sat, 18 Apr 2015 10:56:19 +0900 Subject: [PATCH 043/101] version bump --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6b26a9e..10a50b1 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ from setuptools import setup, Extension -VERSION = ("1", "0", "0-alpha.3") +VERSION = ("1", "0", "0") rapidxml = Extension("rapidxml._rapidxml", define_macros=[('MAJOR_VERSION', VERSION[0]), From 1901312531f6b639fe850d9385bdf8e41d4eb0da Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Sat, 18 Apr 2015 11:16:55 +0900 Subject: [PATCH 044/101] python2 compat hotfix, waiting for better ways to do it --- rapidxml/c_ext/src/attribute_object.cpp | 2 +- .../c_ext/src/attributeiterator_object.cpp | 2 +- rapidxml/c_ext/src/base_object.cpp | 6 +++--- rapidxml/c_ext/src/document_object.cpp | 2 +- rapidxml/c_ext/src/node_object.cpp | 18 +++++++++--------- rapidxml/c_ext/src/nodeiterator_object.cpp | 2 +- rapidxml/c_ext/src/rapidxml_module.cpp | 6 +++--- rapidxml/rapidxml.py | 10 +++++----- 8 files changed, 24 insertions(+), 24 deletions(-) diff --git a/rapidxml/c_ext/src/attribute_object.cpp b/rapidxml/c_ext/src/attribute_object.cpp index 59ef131..43051c8 100644 --- a/rapidxml/c_ext/src/attribute_object.cpp +++ b/rapidxml/c_ext/src/attribute_object.cpp @@ -74,7 +74,7 @@ static PyMethodDef rapidxml_AttributeObject_methods[] = { PyTypeObject rapidxml_AttributeType = { PyVarObject_HEAD_INIT(NULL, 0) - "rapidxml._rapidxml.Attribute", /* tp_name */ + "_rapidxml.Attribute", /* tp_name */ sizeof(rapidxml_AttributeObject), /* tp_basicsize */ 0, /* tp_itemsize */ 0, /* tp_dealloc */ diff --git a/rapidxml/c_ext/src/attributeiterator_object.cpp b/rapidxml/c_ext/src/attributeiterator_object.cpp index 7d4b2da..92862ee 100644 --- a/rapidxml/c_ext/src/attributeiterator_object.cpp +++ b/rapidxml/c_ext/src/attributeiterator_object.cpp @@ -60,7 +60,7 @@ static PyObject* rapidxml_AttributeIteratorObject_iternext(rapidxml_AttributeIte PyTypeObject rapidxml_AttributeIteratorType = { PyVarObject_HEAD_INIT(NULL, 0) - "rapidxml._rapidxml.AttributeIterator", /* tp_name */ + "_rapidxml.AttributeIterator", /* tp_name */ sizeof(rapidxml_AttributeIteratorObject), /* tp_basicsize */ 0, /* tp_itemsize */ reinterpret_cast(rapidxml_AttributeIteratorObject_dealloc), /* tp_dealloc */ diff --git a/rapidxml/c_ext/src/base_object.cpp b/rapidxml/c_ext/src/base_object.cpp index 2d7b540..e94329c 100644 --- a/rapidxml/c_ext/src/base_object.cpp +++ b/rapidxml/c_ext/src/base_object.cpp @@ -48,7 +48,7 @@ static PyObject* rapidxml_BaseObject_copy(rapidxml_BaseObject* self, return NULL; } if (!IS_BASE(other)) { - PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml._rapidxml.Base"); + PyErr_SetString(PyExc_TypeError, "Expected instance of _rapidxml.Base"); return NULL; } self->underlying_obj = reinterpret_cast(other)->underlying_obj; @@ -64,7 +64,7 @@ static PyObject* rapidxml_BaseObject_richcmp(PyObject* obj1, bool c; if (!(IS_BASE(obj1) && IS_BASE(obj2))) { - PyErr_SetString(PyExc_TypeError, "Expected instances of rapidxml._rapidxml.Base"); + PyErr_SetString(PyExc_TypeError, "Expected instances of _rapidxml.Base"); return NULL; } switch (op) { @@ -205,7 +205,7 @@ static PyMethodDef rapidxml_BaseObject_methods[] = { PyTypeObject rapidxml_BaseType = { PyVarObject_HEAD_INIT(NULL, 0) - "rapidxml._rapidxml.Base", /* tp_name */ + "_rapidxml.Base", /* tp_name */ sizeof(rapidxml_BaseObject), /* tp_basicsize */ 0, /* tp_itemsize */ reinterpret_cast(rapidxml_BaseObject_dealloc), /* tp_dealloc */ diff --git a/rapidxml/c_ext/src/document_object.cpp b/rapidxml/c_ext/src/document_object.cpp index 57ab6ea..ee10536 100644 --- a/rapidxml/c_ext/src/document_object.cpp +++ b/rapidxml/c_ext/src/document_object.cpp @@ -164,7 +164,7 @@ static PyMethodDef rapidxml_DocumentObject_methods[] = { PyTypeObject rapidxml_DocumentType = { PyVarObject_HEAD_INIT(NULL, 0) - "rapidxml._rapidxml.Document", /* tp_name */ + "_rapidxml.Document", /* tp_name */ sizeof(rapidxml_DocumentObject), /* tp_basicsize */ 0, /* tp_itemsize */ reinterpret_cast(rapidxml_DocumentObject_dealloc), /* tp_dealloc */ diff --git a/rapidxml/c_ext/src/node_object.cpp b/rapidxml/c_ext/src/node_object.cpp index d41cf8f..57e5bb8 100644 --- a/rapidxml/c_ext/src/node_object.cpp +++ b/rapidxml/c_ext/src/node_object.cpp @@ -173,7 +173,7 @@ static PyObject* rapidxml_NodeObject_prepend_node(rapidxml_NodeObject* self, return NULL; } if (!IS_NODE(node)) { - PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml._rapidxml.Node"); + PyErr_SetString(PyExc_TypeError, "Expected instance of _rapidxml.Node"); return NULL; } static_cast*>(self->base.underlying_obj)->prepend_node @@ -195,7 +195,7 @@ static PyObject* rapidxml_NodeObject_append_node(rapidxml_NodeObject* self, return NULL; } if (!IS_NODE(node)) { - PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml._rapidxml.Node"); + PyErr_SetString(PyExc_TypeError, "Expected instance of _rapidxml.Node"); return NULL; } static_cast*>(self->base.underlying_obj)->append_node @@ -219,7 +219,7 @@ static PyObject* rapidxml_NodeObject_insert_node(rapidxml_NodeObject* self, return NULL; } if (!(IS_NODE(where) && IS_NODE(node))) { - PyErr_SetString(PyExc_TypeError, "Expected instances of rapidxml._rapidxml.Node"); + PyErr_SetString(PyExc_TypeError, "Expected instances of _rapidxml.Node"); return NULL; } static_cast*>(self->base.underlying_obj)->insert_node @@ -263,7 +263,7 @@ static PyObject* rapidxml_NodeObject_remove_node(rapidxml_NodeObject* self, return NULL; } if (!IS_NODE(node)) { - PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml._rapidxml.Node"); + PyErr_SetString(PyExc_TypeError, "Expected instance of _rapidxml.Node"); return NULL; } static_cast*>(self->base.underlying_obj)->remove_node @@ -293,7 +293,7 @@ static PyObject* rapidxml_NodeObject_prepend_attribute(rapidxml_NodeObject* self return NULL; } if (!IS_ATTR(attribute)) { - PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml._rapidxml.Attribute"); + PyErr_SetString(PyExc_TypeError, "Expected instance of _rapidxml.Attribute"); return NULL; } static_cast*>(self->base.underlying_obj)->prepend_attribute @@ -315,7 +315,7 @@ static PyObject* rapidxml_NodeObject_append_attribute(rapidxml_NodeObject* self, return NULL; } if (!IS_ATTR(attribute)) { - PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml._rapidxml.Attribute"); + PyErr_SetString(PyExc_TypeError, "Expected instance of _rapidxml.Attribute"); return NULL; } static_cast*>(self->base.underlying_obj)->append_attribute @@ -339,7 +339,7 @@ static PyObject* rapidxml_NodeObject_insert_attribute(rapidxml_NodeObject* self, return NULL; } if (!(IS_ATTR(where) && IS_ATTR(attribute))) { - PyErr_SetString(PyExc_TypeError, "Expected instances of rapidxml._rapidxml.Attribute"); + PyErr_SetString(PyExc_TypeError, "Expected instances of _rapidxml.Attribute"); return NULL; } static_cast*>(self->base.underlying_obj)->insert_attribute @@ -383,7 +383,7 @@ static PyObject* rapidxml_NodeObject_remove_attribute(rapidxml_NodeObject* self, return NULL; } if (!IS_ATTR(attribute)) { - PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml._rapidxml.Attribute"); + PyErr_SetString(PyExc_TypeError, "Expected instance of _rapidxml.Attribute"); return NULL; } static_cast*>(self->base.underlying_obj)->remove_attribute @@ -531,7 +531,7 @@ static PyMethodDef rapidxml_NodeObject_methods[] = { PyTypeObject rapidxml_NodeType = { PyVarObject_HEAD_INIT(NULL, 0) - "rapidxml._rapidxml.Node", /* tp_name */ + "_rapidxml.Node", /* tp_name */ sizeof(rapidxml_NodeObject), /* tp_basicsize */ 0, /* tp_itemsize */ 0, /* tp_dealloc */ diff --git a/rapidxml/c_ext/src/nodeiterator_object.cpp b/rapidxml/c_ext/src/nodeiterator_object.cpp index 09be49e..4a49b9e 100644 --- a/rapidxml/c_ext/src/nodeiterator_object.cpp +++ b/rapidxml/c_ext/src/nodeiterator_object.cpp @@ -60,7 +60,7 @@ static PyObject* rapidxml_NodeIteratorObject_iternext(rapidxml_NodeIteratorObjec PyTypeObject rapidxml_NodeIteratorType = { PyVarObject_HEAD_INIT(NULL, 0) - "rapidxml._rapidxml.NodeIterator", /* tp_name */ + "_rapidxml.NodeIterator", /* tp_name */ sizeof(rapidxml_NodeIteratorObject), /* tp_basicsize */ 0, /* tp_itemsize */ reinterpret_cast(rapidxml_NodeIteratorObject_dealloc), /* tp_dealloc */ diff --git a/rapidxml/c_ext/src/rapidxml_module.cpp b/rapidxml/c_ext/src/rapidxml_module.cpp index 14599c6..4258455 100644 --- a/rapidxml/c_ext/src/rapidxml_module.cpp +++ b/rapidxml/c_ext/src/rapidxml_module.cpp @@ -22,7 +22,7 @@ static PyMethodDef module_methods[] = { static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, - "rapidxml._rapidxml", + "_rapidxml", "python module for rapidxml bindings", -1, module_methods, @@ -64,7 +64,7 @@ PyMODINIT_FUNC init_rapidxml(void) #if PY_MAJOR_VERSION >= 3 module = PyModule_Create(&moduledef); #else - module = Py_InitModule3("rapidxml._rapidxml", + module = Py_InitModule3("_rapidxml", module_methods, "rapidxml module for rapidxml bindings"); #endif @@ -101,7 +101,7 @@ PyMODINIT_FUNC init_rapidxml(void) "AttributeIterator", reinterpret_cast(&rapidxml_AttributeIteratorType)); - rapidxml_RapidXmlError = PyErr_NewException("rapidxml._rapidxml.RapidXmlError", + rapidxml_RapidXmlError = PyErr_NewException("_rapidxml.RapidXmlError", NULL, NULL); Py_INCREF(rapidxml_RapidXmlError); PyModule_AddObject(module, diff --git a/rapidxml/rapidxml.py b/rapidxml/rapidxml.py index f71e772..691054a 100644 --- a/rapidxml/rapidxml.py +++ b/rapidxml/rapidxml.py @@ -6,11 +6,11 @@ # arzaroth@arzaroth.com # -import rapidxml._rapidxml +import _rapidxml -class DictNode(rapidxml._rapidxml.Node): +class DictNode(_rapidxml.Node): def __init__(self, attribute_prefix='@', cdata_key='#text'): - rapidxml._rapidxml.Node.__init__(self) + _rapidxml.Node.__init__(self) self.attribute_prefix = attribute_prefix self.cdata_key = cdata_key @@ -52,11 +52,11 @@ def __getitem__(self, name): raise KeyError(name) return res -class RapidXml(DictNode, rapidxml._rapidxml.Document): +class RapidXml(DictNode, _rapidxml.Document): def __init__(self, text="", from_file=False, attribute_prefix='@', cdata_key='#text'): DictNode.__init__(self, attribute_prefix, cdata_key) - rapidxml._rapidxml.Document.__init__(self, text, from_file) + _rapidxml.Document.__init__(self, text, from_file) From db6c1fac0f4c96e772febdcc512d85c3b751e266 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Sat, 18 Apr 2015 11:17:33 +0900 Subject: [PATCH 045/101] version bump (1.0.1) --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 10a50b1..2794571 100644 --- a/setup.py +++ b/setup.py @@ -8,9 +8,9 @@ from setuptools import setup, Extension -VERSION = ("1", "0", "0") +VERSION = ("1", "0", "1") -rapidxml = Extension("rapidxml._rapidxml", +rapidxml = Extension("_rapidxml", define_macros=[('MAJOR_VERSION', VERSION[0]), ('MINOR_VERSION', VERSION[1])], include_dirs=[ From a0e1124b95c75d4bb3ef2b857f3127a86a2aeab8 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Sat, 18 Apr 2015 13:31:37 +0900 Subject: [PATCH 046/101] changing arguments type for Document.parse --- rapidxml/c_ext/src/document_object.cpp | 45 +++++++++++++------------- rapidxml/c_ext/src/node_object.cpp | 10 +++--- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/rapidxml/c_ext/src/document_object.cpp b/rapidxml/c_ext/src/document_object.cpp index ee10536..a07a869 100644 --- a/rapidxml/c_ext/src/document_object.cpp +++ b/rapidxml/c_ext/src/document_object.cpp @@ -27,32 +27,38 @@ static PyObject* rapidxml_DocumentObject_parse(rapidxml_DocumentObject* self, PyObject* args, PyObject* kwds) { const char* text = NULL; - int from_file = 0; + PyObject* text_obj = NULL; PyObject* from_file_obj = NULL; char kw_text[] = "text"; char kw_from_file[] = "from_file"; std::vector text_vector; - PyObject* res; static char* kwlist[] = {kw_text, kw_from_file, NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|O", kwlist, - &text, &from_file_obj)) { - goto fail; - } - if (from_file_obj) { - from_file = PyObject_IsTrue(from_file_obj); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, + &text_obj, &from_file_obj)) { + return NULL; } - if (from_file) { + if ((from_file_obj != NULL) && PyObject_IsTrue(from_file_obj)) { + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|O", kwlist, + &text, &from_file_obj)) { + return NULL; + } std::ifstream f(text, std::ios::binary); if (f.fail()) { PyErr_SetString(rapidxml_RapidXmlError, strerror(errno)); - goto fail; + return NULL; } text_vector = std::vector((std::istreambuf_iterator(f)), std::istreambuf_iterator()); text_vector.push_back(0); text = &text_vector[0]; + } else { + if (!PyByteArray_Check(text_obj)) { + PyErr_SetString(PyExc_TypeError, "argument 1 must be bytearray"); + return NULL; + } + text = PyByteArray_AsString(text_obj); } try { self->base.base.document->clear(); @@ -61,21 +67,16 @@ static PyObject* rapidxml_DocumentObject_parse(rapidxml_DocumentObject* self, (self->base.base.document->allocate_string(text)); } catch (rapidxml::parse_error &e) { PyErr_SetString(rapidxml_RapidXmlError, e.what()); - goto fail; + return NULL; } - res = Py_True; - goto end; - fail: - res = Py_False; - end: - Py_INCREF(res); - return res; + Py_INCREF(Py_None); + return Py_None; } static int rapidxml_DocumentObject_init(rapidxml_DocumentObject* self, PyObject* args, PyObject* kwds) { - const char* text = NULL; + PyObject* text_obj = NULL; PyObject* from_file_obj = NULL; char kw_text[] = "text"; char kw_from_file[] = "from_file"; @@ -84,13 +85,13 @@ static int rapidxml_DocumentObject_init(rapidxml_DocumentObject* self, return -1; } static char* kwlist[] = {kw_text, kw_from_file, NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sO", kwlist, - &text, &from_file_obj)) { + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist, + &text_obj, &from_file_obj)) { return -1; } self->base.base.underlying_obj = new rapidxml::xml_document<>(); self->base.base.document = static_cast*>(self->base.base.underlying_obj); - if (text && *text) { + if (text_obj && PyObject_IsTrue(text_obj)) { rapidxml_DocumentObject_parse(self, args, kwds); } return 0; diff --git a/rapidxml/c_ext/src/node_object.cpp b/rapidxml/c_ext/src/node_object.cpp index 57e5bb8..3a438fd 100644 --- a/rapidxml/c_ext/src/node_object.cpp +++ b/rapidxml/c_ext/src/node_object.cpp @@ -410,14 +410,12 @@ static PyObject* rapidxml_NodeObject_unparse(rapidxml_NodeObject* self, char kw_pretty[] = "pretty"; static char* kwlist[] = {kw_pretty, NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &pretty_obj)) { - pretty = 0; - } else if (pretty_obj) { - pretty = PyObject_IsTrue(pretty_obj); - } + PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &pretty_obj); + rapidxml::print(std::back_inserter(xml), *(static_cast*>(self->base.underlying_obj)), - !pretty ? rapidxml::print_no_indenting : 0); + ((pretty_obj == NULL) || PyObject_Not(pretty_obj)) + ? rapidxml::print_no_indenting : 0); return Py_BuildValue("s", xml.c_str()); } From 751860633a75c6026e025cc8e17fb062accd4a2e Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Sat, 18 Apr 2015 13:32:12 +0900 Subject: [PATCH 047/101] version bump --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2794571..5ec3018 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ from setuptools import setup, Extension -VERSION = ("1", "0", "1") +VERSION = ("1", "0", "2") rapidxml = Extension("_rapidxml", define_macros=[('MAJOR_VERSION', VERSION[0]), From 15b23dedabb3834e13384cf3dfd331bdc54a7ef7 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Sun, 19 Apr 2015 09:51:17 +0900 Subject: [PATCH 048/101] contains --- rapidxml/rapidxml.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/rapidxml/rapidxml.py b/rapidxml/rapidxml.py index 691054a..6afd5a1 100644 --- a/rapidxml/rapidxml.py +++ b/rapidxml/rapidxml.py @@ -52,6 +52,13 @@ def __getitem__(self, name): raise KeyError(name) return res + def __contains__(self, name): + try: + self[name] + except: + return False + return True + class RapidXml(DictNode, _rapidxml.Document): def __init__(self, text="", From c3624bf0d37e27688676355da12c2e6e9412c442 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Sun, 19 Apr 2015 09:51:24 +0900 Subject: [PATCH 049/101] version bump --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 5ec3018..81cb471 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ from setuptools import setup, Extension -VERSION = ("1", "0", "2") +VERSION = ("1", "0", "3") rapidxml = Extension("_rapidxml", define_macros=[('MAJOR_VERSION', VERSION[0]), From 116db7a2637b0eb8ec8debdb3ccb50fccb40f10a Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Sun, 19 Apr 2015 10:11:48 +0900 Subject: [PATCH 050/101] dictnode iterator --- rapidxml/rapidxml.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/rapidxml/rapidxml.py b/rapidxml/rapidxml.py index 6afd5a1..0b1e0b2 100644 --- a/rapidxml/rapidxml.py +++ b/rapidxml/rapidxml.py @@ -8,6 +8,20 @@ import _rapidxml +class DictNodeIterator(object): + def __init__(self, iterable): + self._iter = iterable + + def __next__(self): + return self.next() + + def next(self): + return DictNode().copy(next(self._iter)) + + def __iter__(self): + return self + + class DictNode(_rapidxml.Node): def __init__(self, attribute_prefix='@', cdata_key='#text'): _rapidxml.Node.__init__(self) @@ -59,6 +73,10 @@ def __contains__(self, name): return False return True + def __iter__(self): + return DictNodeIterator(self.children) + + class RapidXml(DictNode, _rapidxml.Document): def __init__(self, text="", From 59cc2dcee9e0a5bd2d2b100a302efda0eaaebf6a Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Sun, 19 Apr 2015 10:12:01 +0900 Subject: [PATCH 051/101] version bump --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 81cb471..1b60326 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ from setuptools import setup, Extension -VERSION = ("1", "0", "3") +VERSION = ("1", "0", "4") rapidxml = Extension("_rapidxml", define_macros=[('MAJOR_VERSION', VERSION[0]), From de365d3af590cc16e880058e5bcf70222af67dd2 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Sun, 19 Apr 2015 16:59:35 +0900 Subject: [PATCH 052/101] expose dictnode --- rapidxml/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rapidxml/__init__.py b/rapidxml/__init__.py index 6fee501..5a8ca54 100644 --- a/rapidxml/__init__.py +++ b/rapidxml/__init__.py @@ -6,8 +6,9 @@ # arzaroth@arzaroth.com # -from .rapidxml import RapidXml +from .rapidxml import RapidXml, DictNode __all__ = [ 'RapidXml', + 'DictNode', ] From 9e24fcbb854935d45840085f7f0a39a448bdd866 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Sun, 19 Apr 2015 16:59:55 +0900 Subject: [PATCH 053/101] RapidXml.allocate_node returns dictnode --- rapidxml/rapidxml.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rapidxml/rapidxml.py b/rapidxml/rapidxml.py index 0b1e0b2..7a0f39c 100644 --- a/rapidxml/rapidxml.py +++ b/rapidxml/rapidxml.py @@ -85,3 +85,6 @@ def __init__(self, cdata_key='#text'): DictNode.__init__(self, attribute_prefix, cdata_key) _rapidxml.Document.__init__(self, text, from_file) + + def allocate_node(self, *args): + return DictNode().copy(super(RapidXml, self).allocate_node(*args)) From 3dfcfc33a72d44e5e84236e2c1a6f8b666aee479 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Sun, 19 Apr 2015 17:00:10 +0900 Subject: [PATCH 054/101] version bump --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 1b60326..9940f9f 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ from setuptools import setup, Extension -VERSION = ("1", "0", "4") +VERSION = ("1", "0", "5") rapidxml = Extension("_rapidxml", define_macros=[('MAJOR_VERSION', VERSION[0]), From 35a90c9cb736ebf44507c65dce647f66284f501b Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Tue, 21 Apr 2015 18:38:38 +0900 Subject: [PATCH 055/101] travil.yml --- .travis.yml | 8 ++++++++ README | 43 ++++++++++++++++++++++++++++++++++++------- setup.py | 24 +++++++++++++++++++++--- 3 files changed, 65 insertions(+), 10 deletions(-) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..7dc0606 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,8 @@ +language: python +python: + - "2.6" + - "2.7" + - "3.3" + - "3.4" +install: + - pip install . diff --git a/README b/README index 2126ec3..e5e73d7 100644 --- a/README +++ b/README @@ -1,10 +1,8 @@ -python_rapidxml -=============== +## python_rapidxml A library providing python bindings for rapidxml -Example ---------------- +## Example import rapidxml @@ -24,7 +22,38 @@ Example assert(repr(r) == r.unparse()) # also always True, returns flat version -Project Current State -=============== +## Install -This project is currently under *heavy* development. +[![Latest Version](https://pypip.in/version/RapidXml/badge.svg)](https://pypi.python.org/pypi/RapidXml/) +[![Supported Python Versions](https://pypip.in/py_versions/RapidXml/badge.svg)](https://pypi.python.org/pypi/RapidXml/) + +If you have downloaded the source code: + + python setup.py install + +or if you want to obtain a copy from the Pypi repository: + + pip install rapidxml + +Both commands will install the required package dependencies. + +A distribution package can be obtained for manual installation at: + + http://pypi.python.org/pypi/RapidXml + + +## Source + +python_rapidxml's git repo is available on GitHub, which can be browsed at [github](https://github.com/Arzaroth/python_rapidxml) and cloned like that: + + git clone https://github.com/Arzaroth/python_rapidxml.git + + +## License + +MIT license. See the LICENSE file. + + +## Development status + +This project is currently under development. diff --git a/setup.py b/setup.py index 9940f9f..36c2a24 100644 --- a/setup.py +++ b/setup.py @@ -6,9 +6,9 @@ # arzaroth@arzaroth.com # -from setuptools import setup, Extension +from setuptools import setup, Extension, find_packages -VERSION = ("1", "0", "5") +VERSION = ("1", "0", "6") rapidxml = Extension("_rapidxml", define_macros=[('MAJOR_VERSION', VERSION[0]), @@ -45,5 +45,23 @@ long_description=open('README').read(), keywords='rapidxml xml parsing', - packages=['rapidxml'], + packages=find_packages('.'), + + classifiers=[ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Operating System :: POSIX", + "Operating System :: Microsoft :: Windows", + "Operating System :: MacOS :: MacOS X", + "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.6", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + ], ) From c8c8d8708deef431da421e67689f00ecfe6f0ddc Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Tue, 21 Apr 2015 18:41:42 +0900 Subject: [PATCH 056/101] readme & setup --- README | 10 +++++----- setup.py | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README b/README index e5e73d7..c40b0c0 100644 --- a/README +++ b/README @@ -2,7 +2,7 @@ A library providing python bindings for rapidxml -## Example +### Example import rapidxml @@ -22,7 +22,7 @@ A library providing python bindings for rapidxml assert(repr(r) == r.unparse()) # also always True, returns flat version -## Install +### Install [![Latest Version](https://pypip.in/version/RapidXml/badge.svg)](https://pypi.python.org/pypi/RapidXml/) [![Supported Python Versions](https://pypip.in/py_versions/RapidXml/badge.svg)](https://pypi.python.org/pypi/RapidXml/) @@ -42,18 +42,18 @@ A distribution package can be obtained for manual installation at: http://pypi.python.org/pypi/RapidXml -## Source +### Source python_rapidxml's git repo is available on GitHub, which can be browsed at [github](https://github.com/Arzaroth/python_rapidxml) and cloned like that: git clone https://github.com/Arzaroth/python_rapidxml.git -## License +### License MIT license. See the LICENSE file. -## Development status +### Development status This project is currently under development. diff --git a/setup.py b/setup.py index 36c2a24..1c0f91b 100644 --- a/setup.py +++ b/setup.py @@ -41,8 +41,8 @@ author='Marc-Etienne Barrut', author_email='lekva@arzaroth.com', - description='python bindings for RapidXml, a C++ XML parsing library', - long_description=open('README').read(), + description='Python RapidXml Library' + long_description='python bindings for RapidXml, a C++ XML parsing library', keywords='rapidxml xml parsing', packages=find_packages('.'), From e82488c0f85b448aa41f29fed93992c8aad0cbc6 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Tue, 21 Apr 2015 18:42:11 +0900 Subject: [PATCH 057/101] readme --- README => README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename README => README.md (100%) diff --git a/README b/README.md similarity index 100% rename from README rename to README.md From 6fce2202830687034b7d35ba60ae03a2869f80bd Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Tue, 21 Apr 2015 18:43:28 +0900 Subject: [PATCH 058/101] readme --- README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index c40b0c0..b0fb413 100644 --- a/README.md +++ b/README.md @@ -4,22 +4,22 @@ A library providing python bindings for rapidxml ### Example - import rapidxml + import rapidxml - r = rapidxml.RapidXml("foo") # parsing from string - test = r.first_node("test") # get first node named test - test.name = "foo" # changing node's name to foo - r.first_node("test2").value = "bar" # changing node's value to bar + r = rapidxml.RapidXml("foo") # parsing from string + test = r.first_node("test") # get first node named test + test.name = "foo" # changing node's name to foo + r.first_node("test2").value = "bar" # changing node's value to bar - print(str(r)) # will output prettified string of the xml document - print(test) # also works for nodes + print(str(r)) # will output prettified string of the xml document + print(test) # also works for nodes - with open('dump.xml', 'w') as f: - f.write(str(r)) - r = rapidxml.RapidXml("dump.xml", True) # loading from file + with open('dump.xml', 'w') as f: + f.write(str(r)) + r = rapidxml.RapidXml("dump.xml", True) # loading from file - assert(str(r) == r.unparse(True)) # is always True - assert(repr(r) == r.unparse()) # also always True, returns flat version + assert(str(r) == r.unparse(True)) # is always True + assert(repr(r) == r.unparse()) # also always True, returns flat version ### Install From 5ee377c4a0e9284ede1a83fe783d6a0f9748180c Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Tue, 21 Apr 2015 18:46:49 +0900 Subject: [PATCH 059/101] travis.yml --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7dc0606..06beefb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,4 +5,7 @@ python: - "3.3" - "3.4" install: - - pip install . + - python setup.py install +branches: + only: + - master From e232d9966486f7abb75df9670f7acc561a7d10ca Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Tue, 21 Apr 2015 18:48:11 +0900 Subject: [PATCH 060/101] oups --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 1c0f91b..7d0da43 100644 --- a/setup.py +++ b/setup.py @@ -41,7 +41,7 @@ author='Marc-Etienne Barrut', author_email='lekva@arzaroth.com', - description='Python RapidXml Library' + description='Python RapidXml Library', long_description='python bindings for RapidXml, a C++ XML parsing library', keywords='rapidxml xml parsing', From 972ec02c3453e18c5e5d292284947a5a2184eb9b Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Tue, 21 Apr 2015 18:50:44 +0900 Subject: [PATCH 061/101] travis.yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 06beefb..bd54142 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,8 @@ python: - "2.7" - "3.3" - "3.4" -install: - - python setup.py install +install: true +script: python setup.py build branches: only: - master From 4f5ad9624fd4f2178928ca84f77e3d634df4e002 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Tue, 21 Apr 2015 18:55:23 +0900 Subject: [PATCH 062/101] readme & travis --- .travis.yml | 1 + README.md | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index bd54142..2fbe25f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,3 +9,4 @@ script: python setup.py build branches: only: - master + - 1.0 diff --git a/README.md b/README.md index b0fb413..925fe3b 100644 --- a/README.md +++ b/README.md @@ -56,4 +56,6 @@ MIT license. See the LICENSE file. ### Development status +[![Build Status](https://travis-ci.org/Arzaroth/python_rapidxml.svg?branch=1.0)](https://travis-ci.org/Arzaroth/python_rapidxml) + This project is currently under development. From 45de0a40a849d208dd67df4308e48fa2f498fc22 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Tue, 21 Apr 2015 18:57:03 +0900 Subject: [PATCH 063/101] travis --- .travis.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2fbe25f..1a7c945 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,5 @@ python: install: true script: python setup.py build branches: - only: - - master - - 1.0 + except: + - dev From 3670687d150ba848cfb72b5d96824abfa63fd56e Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Tue, 21 Apr 2015 19:31:41 +0900 Subject: [PATCH 064/101] tranfering attributes to dictnodes --- rapidxml/c_ext/src/document_object.cpp | 2 +- rapidxml/c_ext/src/node_object.cpp | 1 - rapidxml/rapidxml.py | 42 +++++++++++++++++++------- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/rapidxml/c_ext/src/document_object.cpp b/rapidxml/c_ext/src/document_object.cpp index a07a869..5496f91 100644 --- a/rapidxml/c_ext/src/document_object.cpp +++ b/rapidxml/c_ext/src/document_object.cpp @@ -19,7 +19,7 @@ #include static void rapidxml_DocumentObject_dealloc(rapidxml_DocumentObject* self) { - delete self->base.base.underlying_obj; + delete self->base.base.document; Py_TYPE(self)->tp_free(reinterpret_cast(self)); } diff --git a/rapidxml/c_ext/src/node_object.cpp b/rapidxml/c_ext/src/node_object.cpp index 3a438fd..b46c4d1 100644 --- a/rapidxml/c_ext/src/node_object.cpp +++ b/rapidxml/c_ext/src/node_object.cpp @@ -404,7 +404,6 @@ static PyObject* rapidxml_NodeObject_remove_all_attributes(rapidxml_NodeObject* static PyObject* rapidxml_NodeObject_unparse(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { - int pretty = 0; PyObject* pretty_obj = NULL; std::string xml; char kw_pretty[] = "pretty"; diff --git a/rapidxml/rapidxml.py b/rapidxml/rapidxml.py index 7a0f39c..3ad6831 100644 --- a/rapidxml/rapidxml.py +++ b/rapidxml/rapidxml.py @@ -9,35 +9,49 @@ import _rapidxml class DictNodeIterator(object): - def __init__(self, iterable): + def __init__(self, + iterable, + attribute_prefix, + cdata_key, + always_aslist): self._iter = iterable + self.attribute_prefix = attribute_prefix + self.cdata_key = cdata_key + self.always_aslist = always_aslist def __next__(self): return self.next() def next(self): - return DictNode().copy(next(self._iter)) + return DictNode(self.attribute_prefix, + self.cdata_key, + self.always_aslist).copy(next(self._iter)) def __iter__(self): return self class DictNode(_rapidxml.Node): - def __init__(self, attribute_prefix='@', cdata_key='#text'): + def __init__(self, attribute_prefix='@', cdata_key='#text', always_aslist=False): _rapidxml.Node.__init__(self) self.attribute_prefix = attribute_prefix self.cdata_key = cdata_key + self.always_aslist = always_aslist def get_nodes(self, name): node = self.first_node(name) if node is None: return None - res = [DictNode(self.attribute_prefix, self.cdata_key).copy(node)] + res = [DictNode(self.attribute_prefix, + self.cdata_key, + self.always_aslist).copy(node)] node = node.next_sibling(name) - if node is None: + if node is None and not self.always_aslist: return res[0] while node is not None: - res.append(DictNode(self.attribute_prefix, self.cdata_key).copy(node)) + res.append(DictNode(self.attribute_prefix, + self.cdata_key, + self.always_aslist).copy(node)) node = node.next_sibling(name) return res @@ -47,7 +61,7 @@ def get_attributes(self, name): return None res = [attribute] attribute = attribute.next_attribute(name) - if attribute is None: + if attribute is None and not self.always_aslist: return res[0] while attribute is not None: res.append(attribute) @@ -74,7 +88,10 @@ def __contains__(self, name): return True def __iter__(self): - return DictNodeIterator(self.children) + return DictNodeIterator(self.children, + self.attribute_prefix, + self.cdata_key, + self.always_aslist) class RapidXml(DictNode, _rapidxml.Document): @@ -82,9 +99,12 @@ def __init__(self, text="", from_file=False, attribute_prefix='@', - cdata_key='#text'): - DictNode.__init__(self, attribute_prefix, cdata_key) + cdata_key='#text', + always_aslist=False): + DictNode.__init__(self, attribute_prefix, cdata_key, always_aslist) _rapidxml.Document.__init__(self, text, from_file) def allocate_node(self, *args): - return DictNode().copy(super(RapidXml, self).allocate_node(*args)) + return DictNode(self.attribute_prefix, + self.cdata_key, + self.always_aslist).copy(super(RapidXml, self).allocate_node(*args)) From b6667f5706f7a8812bbf37454098e3729a0562c2 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Thu, 23 Apr 2015 12:34:11 +0900 Subject: [PATCH 065/101] unit tests using pytest --- .travis.yml | 7 +++-- test-requirements.txt | 2 ++ test/simple.py | 31 --------------------- tests/test_simple.py | 65 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 33 deletions(-) create mode 100644 test-requirements.txt delete mode 100755 test/simple.py create mode 100755 tests/test_simple.py diff --git a/.travis.yml b/.travis.yml index 1a7c945..7d66f9c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,8 +4,11 @@ python: - "2.7" - "3.3" - "3.4" -install: true -script: python setup.py build +install: + - pip install -r test-requirements.txt + - python setup.py install +script: + - py.test -sv tests branches: except: - dev diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 0000000..e004cf0 --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1,2 @@ +py==1.4.26 +pytest==2.7.0 diff --git a/test/simple.py b/test/simple.py deleted file mode 100755 index 866878b..0000000 --- a/test/simple.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# File: simple.py -# by Arzaroth Lekva -# arzaroth@arzaroth.com -# -import rapidxml - -r = rapidxml.RapidXml("foo") # parsing from string -test = r.first_node("test") # get first node named test -assert(test.name == "test") -assert(test.value == "") -test.name = "foo" # changing node's name to foo -assert(test.name == "foo") - -test2 = r.first_node("test2") -assert(test2.name == "test2") -assert(test2.value == "foo") -test2.value = "bar" # changing node's value to bar -assert(test2.value == "bar") - -print(str(r)) # will output prettified string of the xml document -print(test) # also works for nodes - -with open('dump.xml', 'w') as f: - f.write(str(r)) -r = rapidxml.RapidXml("dump.xml", True) # loading from file - -assert(str(r) == r.unparse(True)) # is always True -assert(repr(r) == r.unparse()) # also always True, returns flat version diff --git a/tests/test_simple.py b/tests/test_simple.py new file mode 100755 index 0000000..9d79761 --- /dev/null +++ b/tests/test_simple.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# File: simple.py +# by Arzaroth Lekva +# arzaroth@arzaroth.com +# + +import pytest +import os +import rapidxml + +@pytest.fixture() +def init_rapidxml(): + r = rapidxml.RapidXml(bytearray(b""" + + + + + + + + some text +""")) + return r + +def test_init(init_rapidxml): + assert init_rapidxml.unparse() == ('' + '' + 'some text') + +def test_parse(init_rapidxml): + r = rapidxml.RapidXml() + try: + data = init_rapidxml.unparse().encode('utf-8') + except UnicodeDecodeError: + data = init_rapidxml.unparse() + r.parse(bytearray(data)) + assert str(r) == str(init_rapidxml) + +def test_parse_from_file(init_rapidxml, tmpdir): + f = tmpdir.join("dump.xml") + f.write(init_rapidxml.unparse()) + r = rapidxml.RapidXml(str(f), from_file=True) + assert str(r) == str(init_rapidxml) + +def test_first_node(init_rapidxml): + root = init_rapidxml.first_node() + assert root.name == "root" + assert root.value == "" + assert root.unparse() == init_rapidxml.unparse() + +def test_nested_node(init_rapidxml): + test = init_rapidxml.first_node().first_node("test") + assert test.name == "test" + assert test.value == "" + test2 = init_rapidxml.first_node().first_node("test2") + assert test2.name == "test2" + assert test2.value == "" + +def test_children(init_rapidxml): + test2 = init_rapidxml.first_node().first_node("test2") + for node in test2.children: + assert node.name == "node" + assert node.value == "" From 07e4b7c9649db0ed20f6469be8ee9afa3c2f5bc9 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Thu, 23 Apr 2015 12:40:19 +0900 Subject: [PATCH 066/101] base object not equals --- rapidxml/c_ext/src/base_object.cpp | 4 ++++ tests/test_simple.py | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/rapidxml/c_ext/src/base_object.cpp b/rapidxml/c_ext/src/base_object.cpp index e94329c..105ded5 100644 --- a/rapidxml/c_ext/src/base_object.cpp +++ b/rapidxml/c_ext/src/base_object.cpp @@ -72,6 +72,10 @@ static PyObject* rapidxml_BaseObject_richcmp(PyObject* obj1, c = (reinterpret_cast(obj1)->underlying_obj == reinterpret_cast(obj2)->underlying_obj); break; + case Py_NE: + c = (reinterpret_cast(obj1)->underlying_obj != + reinterpret_cast(obj2)->underlying_obj); + break; default: PyErr_SetNone(PyExc_NotImplementedError); return NULL; diff --git a/tests/test_simple.py b/tests/test_simple.py index 9d79761..6fc6255 100755 --- a/tests/test_simple.py +++ b/tests/test_simple.py @@ -28,6 +28,8 @@ def test_init(init_rapidxml): assert init_rapidxml.unparse() == ('' '' 'some text') + assert init_rapidxml.unparse() == repr(init_rapidxml) + assert init_rapidxml.unparse(True) == str(init_rapidxml) def test_parse(init_rapidxml): r = rapidxml.RapidXml() @@ -44,6 +46,13 @@ def test_parse_from_file(init_rapidxml, tmpdir): r = rapidxml.RapidXml(str(f), from_file=True) assert str(r) == str(init_rapidxml) +def test_equals(init_rapidxml): + assert init_rapidxml == init_rapidxml + root = init_rapidxml.first_node() + assert root == init_rapidxml.first_node() + assert root.first_node() != root.first_node("test2") + assert (root != root) == (not (root == root)) + def test_first_node(init_rapidxml): root = init_rapidxml.first_node() assert root.name == "root" From 50ffc39d3542e48ab56e9eeb83a32e14e74f53e1 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Thu, 23 Apr 2015 12:59:55 +0900 Subject: [PATCH 067/101] more tests --- tests/test_simple.py | 74 -------------------------------------------- 1 file changed, 74 deletions(-) delete mode 100755 tests/test_simple.py diff --git a/tests/test_simple.py b/tests/test_simple.py deleted file mode 100755 index 6fc6255..0000000 --- a/tests/test_simple.py +++ /dev/null @@ -1,74 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# File: simple.py -# by Arzaroth Lekva -# arzaroth@arzaroth.com -# - -import pytest -import os -import rapidxml - -@pytest.fixture() -def init_rapidxml(): - r = rapidxml.RapidXml(bytearray(b""" - - - - - - - - some text -""")) - return r - -def test_init(init_rapidxml): - assert init_rapidxml.unparse() == ('' - '' - 'some text') - assert init_rapidxml.unparse() == repr(init_rapidxml) - assert init_rapidxml.unparse(True) == str(init_rapidxml) - -def test_parse(init_rapidxml): - r = rapidxml.RapidXml() - try: - data = init_rapidxml.unparse().encode('utf-8') - except UnicodeDecodeError: - data = init_rapidxml.unparse() - r.parse(bytearray(data)) - assert str(r) == str(init_rapidxml) - -def test_parse_from_file(init_rapidxml, tmpdir): - f = tmpdir.join("dump.xml") - f.write(init_rapidxml.unparse()) - r = rapidxml.RapidXml(str(f), from_file=True) - assert str(r) == str(init_rapidxml) - -def test_equals(init_rapidxml): - assert init_rapidxml == init_rapidxml - root = init_rapidxml.first_node() - assert root == init_rapidxml.first_node() - assert root.first_node() != root.first_node("test2") - assert (root != root) == (not (root == root)) - -def test_first_node(init_rapidxml): - root = init_rapidxml.first_node() - assert root.name == "root" - assert root.value == "" - assert root.unparse() == init_rapidxml.unparse() - -def test_nested_node(init_rapidxml): - test = init_rapidxml.first_node().first_node("test") - assert test.name == "test" - assert test.value == "" - test2 = init_rapidxml.first_node().first_node("test2") - assert test2.name == "test2" - assert test2.value == "" - -def test_children(init_rapidxml): - test2 = init_rapidxml.first_node().first_node("test2") - for node in test2.children: - assert node.name == "node" - assert node.value == "" From 0c521b1fd211406e0cc9904e0112753873f2f75b Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Thu, 23 Apr 2015 13:00:02 +0900 Subject: [PATCH 068/101] more tests --- tests/conftest.py | 24 ++++++++++++++ tests/test_basic.py | 69 ++++++++++++++++++++++++++++++++++++++++ tests/test_iterations.py | 31 ++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 tests/conftest.py create mode 100755 tests/test_basic.py create mode 100644 tests/test_iterations.py diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..8f0939d --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# File: conftest.py +# by Arzaroth Lekva +# arzaroth@arzaroth.com +# + +import pytest +import rapidxml + +@pytest.fixture(scope="session") +def init_rapidxml(): + r = rapidxml.RapidXml(bytearray(b""" + + + + + + + + some text +""")) + return r diff --git a/tests/test_basic.py b/tests/test_basic.py new file mode 100755 index 0000000..2703ab6 --- /dev/null +++ b/tests/test_basic.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# File: simple.py +# by Arzaroth Lekva +# arzaroth@arzaroth.com +# + +import os +import rapidxml + +def test_init(init_rapidxml): + assert init_rapidxml.unparse() == ('' + '' + 'some text') + assert init_rapidxml.unparse() == repr(init_rapidxml) + assert init_rapidxml.unparse(True) == str(init_rapidxml) + +def test_parse(init_rapidxml): + r = rapidxml.RapidXml() + try: + data = init_rapidxml.unparse().encode('utf-8') + except UnicodeDecodeError: + data = init_rapidxml.unparse() + r.parse(bytearray(data)) + assert str(r) == str(init_rapidxml) + +def test_parse_from_file(init_rapidxml, tmpdir): + f = tmpdir.join("dump.xml") + f.write(init_rapidxml.unparse()) + r = rapidxml.RapidXml(str(f), from_file=True) + assert str(r) == str(init_rapidxml) + +def test_equals(init_rapidxml): + assert init_rapidxml == init_rapidxml + root = init_rapidxml.first_node() + assert root == root + assert root == init_rapidxml.first_node() + assert root.first_node() != root.first_node("test2") + assert (root != root) == (not (root == root)) + +def test_first_node(init_rapidxml): + root = init_rapidxml.first_node() + assert root.name == "root" + assert root.value == "" + assert root.unparse() == init_rapidxml.unparse() + +def test_nested_node(init_rapidxml): + test = init_rapidxml.first_node().first_node("test") + assert test.name == "test" + assert test.value == "" + test2 = init_rapidxml.first_node().first_node("test2") + assert test2.name == "test2" + assert test2.value == "" + +def test_assign(init_rapidxml): + root = init_rapidxml.first_node() + root.name = "new_root" + assert root.name == "new_root" + test = root.first_node() + test.name = "new_test" + test.first_attribute().name = "new_attr1" + test.first_attribute().next_attribute().value = "new_two" + test = root.first_node("test") + test.value = "some new text" + assert test.value == "some new text" + assert init_rapidxml.unparse() == ('' + '' + 'some new text') diff --git a/tests/test_iterations.py b/tests/test_iterations.py new file mode 100644 index 0000000..bdc3030 --- /dev/null +++ b/tests/test_iterations.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# File: test_iterations.py +# by Arzaroth Lekva +# arzaroth@arzaroth.com +# + +def test_children(init_rapidxml): + test2 = init_rapidxml.first_node().first_node("test2") + i_node = test2.first_node() + for node in test2.children: + assert i_node == node + assert node.name == "node" + assert node.value == "" + i_node = i_node.next_sibling() + if i_node: + assert i_node != node + +def test_attributes(init_rapidxml): + test = init_rapidxml.first_node().first_node() + i_attr = test.first_attribute() + for attr, expected_attr in zip(test.attributes, [('attr1', 'one'), + ('attr2', 'two'), + ('attr3', 'three')]): + assert i_attr == attr + assert (attr.name, attr.value) == expected_attr + assert (i_attr.name, i_attr.value) == expected_attr + i_attr = i_attr.next_attribute() + if i_attr: + assert i_attr != attr From e2985538a188bd3919ff24397dcee3d444118039 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Thu, 23 Apr 2015 13:00:56 +0900 Subject: [PATCH 069/101] scope of fixture --- tests/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 8f0939d..fa9ffd7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -9,7 +9,7 @@ import pytest import rapidxml -@pytest.fixture(scope="session") +@pytest.fixture(scope="function") def init_rapidxml(): r = rapidxml.RapidXml(bytearray(b""" From 6d2b87a994f1c49fadfa31c29f56b523f8575d15 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Thu, 23 Apr 2015 13:17:25 +0900 Subject: [PATCH 070/101] more and more tests --- tests/test_attributes.py | 23 +++++++++++++++++++++++ tests/test_basic.py | 16 +++------------- tests/test_iterations.py | 4 ++-- tests/test_nodes.py | 29 +++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 15 deletions(-) create mode 100644 tests/test_attributes.py mode change 100755 => 100644 tests/test_basic.py create mode 100644 tests/test_nodes.py diff --git a/tests/test_attributes.py b/tests/test_attributes.py new file mode 100644 index 0000000..a761ea4 --- /dev/null +++ b/tests/test_attributes.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# File: test_attributes.py +# by Arzaroth Lekva +# arzaroth@arzaroth.com +# + +def test_first_attribute(init_rapidxml): + test = init_rapidxml.first_node().first_node("test") + assert test.first_attribute().name == "attr1" + assert test.first_attribute().value == "one" + attr2 = test.first_attribute("attr2") + assert attr2.name == "attr2" + assert attr2.value == "two" + +def test_last_attribute(init_rapidxml): + test = init_rapidxml.first_node().first_node("test") + assert test.last_attribute().name == "attr3" + assert test.last_attribute().value == "three" + attr2 = test.last_attribute("attr2") + assert attr2.name == "attr2" + assert attr2.value == "two" diff --git a/tests/test_basic.py b/tests/test_basic.py old mode 100755 new mode 100644 index 2703ab6..fcbc1fa --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -39,19 +39,9 @@ def test_equals(init_rapidxml): assert root.first_node() != root.first_node("test2") assert (root != root) == (not (root == root)) -def test_first_node(init_rapidxml): - root = init_rapidxml.first_node() - assert root.name == "root" - assert root.value == "" - assert root.unparse() == init_rapidxml.unparse() - -def test_nested_node(init_rapidxml): - test = init_rapidxml.first_node().first_node("test") - assert test.name == "test" - assert test.value == "" - test2 = init_rapidxml.first_node().first_node("test2") - assert test2.name == "test2" - assert test2.value == "" +def test_parent(init_rapidxml): + assert init_rapidxml.parent is None + assert init_rapidxml.first_node().parent == init_rapidxml def test_assign(init_rapidxml): root = init_rapidxml.first_node() diff --git a/tests/test_iterations.py b/tests/test_iterations.py index bdc3030..fd38f9f 100644 --- a/tests/test_iterations.py +++ b/tests/test_iterations.py @@ -15,7 +15,7 @@ def test_children(init_rapidxml): assert node.value == "" i_node = i_node.next_sibling() if i_node: - assert i_node != node + assert i_node.previous_sibling() == node def test_attributes(init_rapidxml): test = init_rapidxml.first_node().first_node() @@ -28,4 +28,4 @@ def test_attributes(init_rapidxml): assert (i_attr.name, i_attr.value) == expected_attr i_attr = i_attr.next_attribute() if i_attr: - assert i_attr != attr + assert i_attr.previous_attribute() == attr diff --git a/tests/test_nodes.py b/tests/test_nodes.py new file mode 100644 index 0000000..4efde16 --- /dev/null +++ b/tests/test_nodes.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# File: test_nodes.py +# by Arzaroth Lekva +# arzaroth@arzaroth.com +# + +def test_first_node(init_rapidxml): + root = init_rapidxml.first_node() + assert root.name == "root" + assert root.value == "" + assert root.unparse() == init_rapidxml.unparse() + assert root.first_node() == root.first_node("test") + assert root.first_node() != root.first_node("test2") + +def test_last_node(init_rapidxml): + root = init_rapidxml.first_node() + assert root.first_node() != root.last_node() + assert root.first_node("test2") == root.last_node("test2") + assert root.last_node().value == "some text" + +def test_nested_node(init_rapidxml): + test = init_rapidxml.first_node().first_node("test") + assert test.name == "test" + assert test.value == "" + test2 = init_rapidxml.first_node().first_node("test2") + assert test2.name == "test2" + assert test2.value == "" From b3e8df97f1d2926d484c87b3378fbdeb9f930af2 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Thu, 23 Apr 2015 13:20:27 +0900 Subject: [PATCH 071/101] version bump --- MANIFEST.in | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index 54662c4..b61e77c 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,4 +2,4 @@ include setup.py recursive-include rapidxml/c_ext/inc *.h *.hpp -prune test +prune tests diff --git a/setup.py b/setup.py index 7d0da43..82a247d 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ from setuptools import setup, Extension, find_packages -VERSION = ("1", "0", "6") +VERSION = ("1", "0", "7") rapidxml = Extension("_rapidxml", define_macros=[('MAJOR_VERSION', VERSION[0]), From 7f452da991ae3993118a3d787a5db8358dbcf42f Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Thu, 30 Apr 2015 02:49:45 +0900 Subject: [PATCH 072/101] renaming extension --- rapidxml/c_ext/src/attribute_object.cpp | 2 +- .../c_ext/src/attributeiterator_object.cpp | 2 +- rapidxml/c_ext/src/base_object.cpp | 6 +++--- rapidxml/c_ext/src/document_object.cpp | 2 +- rapidxml/c_ext/src/node_object.cpp | 18 +++++++++--------- rapidxml/c_ext/src/nodeiterator_object.cpp | 2 +- rapidxml/c_ext/src/rapidxml_module.cpp | 10 +++++----- rapidxml/rapidxml.py | 11 ++++++----- setup.py | 4 ++-- 9 files changed, 29 insertions(+), 28 deletions(-) diff --git a/rapidxml/c_ext/src/attribute_object.cpp b/rapidxml/c_ext/src/attribute_object.cpp index 43051c8..95ff875 100644 --- a/rapidxml/c_ext/src/attribute_object.cpp +++ b/rapidxml/c_ext/src/attribute_object.cpp @@ -74,7 +74,7 @@ static PyMethodDef rapidxml_AttributeObject_methods[] = { PyTypeObject rapidxml_AttributeType = { PyVarObject_HEAD_INIT(NULL, 0) - "_rapidxml.Attribute", /* tp_name */ + "rapidxml.c_ext.Attribute", /* tp_name */ sizeof(rapidxml_AttributeObject), /* tp_basicsize */ 0, /* tp_itemsize */ 0, /* tp_dealloc */ diff --git a/rapidxml/c_ext/src/attributeiterator_object.cpp b/rapidxml/c_ext/src/attributeiterator_object.cpp index 92862ee..cd42ed1 100644 --- a/rapidxml/c_ext/src/attributeiterator_object.cpp +++ b/rapidxml/c_ext/src/attributeiterator_object.cpp @@ -60,7 +60,7 @@ static PyObject* rapidxml_AttributeIteratorObject_iternext(rapidxml_AttributeIte PyTypeObject rapidxml_AttributeIteratorType = { PyVarObject_HEAD_INIT(NULL, 0) - "_rapidxml.AttributeIterator", /* tp_name */ + "rapidxml.c_ext.AttributeIterator", /* tp_name */ sizeof(rapidxml_AttributeIteratorObject), /* tp_basicsize */ 0, /* tp_itemsize */ reinterpret_cast(rapidxml_AttributeIteratorObject_dealloc), /* tp_dealloc */ diff --git a/rapidxml/c_ext/src/base_object.cpp b/rapidxml/c_ext/src/base_object.cpp index 105ded5..b006146 100644 --- a/rapidxml/c_ext/src/base_object.cpp +++ b/rapidxml/c_ext/src/base_object.cpp @@ -48,7 +48,7 @@ static PyObject* rapidxml_BaseObject_copy(rapidxml_BaseObject* self, return NULL; } if (!IS_BASE(other)) { - PyErr_SetString(PyExc_TypeError, "Expected instance of _rapidxml.Base"); + PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml.c_ext.Base"); return NULL; } self->underlying_obj = reinterpret_cast(other)->underlying_obj; @@ -64,7 +64,7 @@ static PyObject* rapidxml_BaseObject_richcmp(PyObject* obj1, bool c; if (!(IS_BASE(obj1) && IS_BASE(obj2))) { - PyErr_SetString(PyExc_TypeError, "Expected instances of _rapidxml.Base"); + PyErr_SetString(PyExc_TypeError, "Expected instances of rapidxml.c_ext.Base"); return NULL; } switch (op) { @@ -209,7 +209,7 @@ static PyMethodDef rapidxml_BaseObject_methods[] = { PyTypeObject rapidxml_BaseType = { PyVarObject_HEAD_INIT(NULL, 0) - "_rapidxml.Base", /* tp_name */ + "rapidxml.c_ext.Base", /* tp_name */ sizeof(rapidxml_BaseObject), /* tp_basicsize */ 0, /* tp_itemsize */ reinterpret_cast(rapidxml_BaseObject_dealloc), /* tp_dealloc */ diff --git a/rapidxml/c_ext/src/document_object.cpp b/rapidxml/c_ext/src/document_object.cpp index 5496f91..80669be 100644 --- a/rapidxml/c_ext/src/document_object.cpp +++ b/rapidxml/c_ext/src/document_object.cpp @@ -165,7 +165,7 @@ static PyMethodDef rapidxml_DocumentObject_methods[] = { PyTypeObject rapidxml_DocumentType = { PyVarObject_HEAD_INIT(NULL, 0) - "_rapidxml.Document", /* tp_name */ + "rapidxml.c_ext.Document", /* tp_name */ sizeof(rapidxml_DocumentObject), /* tp_basicsize */ 0, /* tp_itemsize */ reinterpret_cast(rapidxml_DocumentObject_dealloc), /* tp_dealloc */ diff --git a/rapidxml/c_ext/src/node_object.cpp b/rapidxml/c_ext/src/node_object.cpp index b46c4d1..a5ff191 100644 --- a/rapidxml/c_ext/src/node_object.cpp +++ b/rapidxml/c_ext/src/node_object.cpp @@ -173,7 +173,7 @@ static PyObject* rapidxml_NodeObject_prepend_node(rapidxml_NodeObject* self, return NULL; } if (!IS_NODE(node)) { - PyErr_SetString(PyExc_TypeError, "Expected instance of _rapidxml.Node"); + PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml.c_ext.Node"); return NULL; } static_cast*>(self->base.underlying_obj)->prepend_node @@ -195,7 +195,7 @@ static PyObject* rapidxml_NodeObject_append_node(rapidxml_NodeObject* self, return NULL; } if (!IS_NODE(node)) { - PyErr_SetString(PyExc_TypeError, "Expected instance of _rapidxml.Node"); + PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml.c_ext.Node"); return NULL; } static_cast*>(self->base.underlying_obj)->append_node @@ -219,7 +219,7 @@ static PyObject* rapidxml_NodeObject_insert_node(rapidxml_NodeObject* self, return NULL; } if (!(IS_NODE(where) && IS_NODE(node))) { - PyErr_SetString(PyExc_TypeError, "Expected instances of _rapidxml.Node"); + PyErr_SetString(PyExc_TypeError, "Expected instances of rapidxml.c_ext.Node"); return NULL; } static_cast*>(self->base.underlying_obj)->insert_node @@ -263,7 +263,7 @@ static PyObject* rapidxml_NodeObject_remove_node(rapidxml_NodeObject* self, return NULL; } if (!IS_NODE(node)) { - PyErr_SetString(PyExc_TypeError, "Expected instance of _rapidxml.Node"); + PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml.c_ext.Node"); return NULL; } static_cast*>(self->base.underlying_obj)->remove_node @@ -293,7 +293,7 @@ static PyObject* rapidxml_NodeObject_prepend_attribute(rapidxml_NodeObject* self return NULL; } if (!IS_ATTR(attribute)) { - PyErr_SetString(PyExc_TypeError, "Expected instance of _rapidxml.Attribute"); + PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml.c_ext.Attribute"); return NULL; } static_cast*>(self->base.underlying_obj)->prepend_attribute @@ -315,7 +315,7 @@ static PyObject* rapidxml_NodeObject_append_attribute(rapidxml_NodeObject* self, return NULL; } if (!IS_ATTR(attribute)) { - PyErr_SetString(PyExc_TypeError, "Expected instance of _rapidxml.Attribute"); + PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml.c_ext.Attribute"); return NULL; } static_cast*>(self->base.underlying_obj)->append_attribute @@ -339,7 +339,7 @@ static PyObject* rapidxml_NodeObject_insert_attribute(rapidxml_NodeObject* self, return NULL; } if (!(IS_ATTR(where) && IS_ATTR(attribute))) { - PyErr_SetString(PyExc_TypeError, "Expected instances of _rapidxml.Attribute"); + PyErr_SetString(PyExc_TypeError, "Expected instances of rapidxml.c_ext.Attribute"); return NULL; } static_cast*>(self->base.underlying_obj)->insert_attribute @@ -383,7 +383,7 @@ static PyObject* rapidxml_NodeObject_remove_attribute(rapidxml_NodeObject* self, return NULL; } if (!IS_ATTR(attribute)) { - PyErr_SetString(PyExc_TypeError, "Expected instance of _rapidxml.Attribute"); + PyErr_SetString(PyExc_TypeError, "Expected instance of rapidxml.c_ext.Attribute"); return NULL; } static_cast*>(self->base.underlying_obj)->remove_attribute @@ -528,7 +528,7 @@ static PyMethodDef rapidxml_NodeObject_methods[] = { PyTypeObject rapidxml_NodeType = { PyVarObject_HEAD_INIT(NULL, 0) - "_rapidxml.Node", /* tp_name */ + "rapidxml.c_ext.Node", /* tp_name */ sizeof(rapidxml_NodeObject), /* tp_basicsize */ 0, /* tp_itemsize */ 0, /* tp_dealloc */ diff --git a/rapidxml/c_ext/src/nodeiterator_object.cpp b/rapidxml/c_ext/src/nodeiterator_object.cpp index 4a49b9e..9c5616a 100644 --- a/rapidxml/c_ext/src/nodeiterator_object.cpp +++ b/rapidxml/c_ext/src/nodeiterator_object.cpp @@ -60,7 +60,7 @@ static PyObject* rapidxml_NodeIteratorObject_iternext(rapidxml_NodeIteratorObjec PyTypeObject rapidxml_NodeIteratorType = { PyVarObject_HEAD_INIT(NULL, 0) - "_rapidxml.NodeIterator", /* tp_name */ + "rapidxml.c_ext.NodeIterator", /* tp_name */ sizeof(rapidxml_NodeIteratorObject), /* tp_basicsize */ 0, /* tp_itemsize */ reinterpret_cast(rapidxml_NodeIteratorObject_dealloc), /* tp_dealloc */ diff --git a/rapidxml/c_ext/src/rapidxml_module.cpp b/rapidxml/c_ext/src/rapidxml_module.cpp index 4258455..ab02ed6 100644 --- a/rapidxml/c_ext/src/rapidxml_module.cpp +++ b/rapidxml/c_ext/src/rapidxml_module.cpp @@ -22,7 +22,7 @@ static PyMethodDef module_methods[] = { static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, - "_rapidxml", + "rapidxml.c_ext", "python module for rapidxml bindings", -1, module_methods, @@ -34,12 +34,12 @@ static struct PyModuleDef moduledef = { # define INITERROR return NULL -PyMODINIT_FUNC PyInit__rapidxml(void) +PyMODINIT_FUNC PyInit_c_ext(void) #else # define INITERROR return -PyMODINIT_FUNC init_rapidxml(void) +PyMODINIT_FUNC initc_ext(void) #endif { PyObject* module; @@ -64,7 +64,7 @@ PyMODINIT_FUNC init_rapidxml(void) #if PY_MAJOR_VERSION >= 3 module = PyModule_Create(&moduledef); #else - module = Py_InitModule3("_rapidxml", + module = Py_InitModule3("rapidxml.c_ext", module_methods, "rapidxml module for rapidxml bindings"); #endif @@ -101,7 +101,7 @@ PyMODINIT_FUNC init_rapidxml(void) "AttributeIterator", reinterpret_cast(&rapidxml_AttributeIteratorType)); - rapidxml_RapidXmlError = PyErr_NewException("_rapidxml.RapidXmlError", + rapidxml_RapidXmlError = PyErr_NewException("rapidxml.c_ext.RapidXmlError", NULL, NULL); Py_INCREF(rapidxml_RapidXmlError); PyModule_AddObject(module, diff --git a/rapidxml/rapidxml.py b/rapidxml/rapidxml.py index 3ad6831..268529d 100644 --- a/rapidxml/rapidxml.py +++ b/rapidxml/rapidxml.py @@ -6,7 +6,8 @@ # arzaroth@arzaroth.com # -import _rapidxml +from __future__ import absolute_import +import rapidxml.c_ext class DictNodeIterator(object): def __init__(self, @@ -31,9 +32,9 @@ def __iter__(self): return self -class DictNode(_rapidxml.Node): +class DictNode(rapidxml.c_ext.Node): def __init__(self, attribute_prefix='@', cdata_key='#text', always_aslist=False): - _rapidxml.Node.__init__(self) + rapidxml.c_ext.Node.__init__(self) self.attribute_prefix = attribute_prefix self.cdata_key = cdata_key self.always_aslist = always_aslist @@ -94,7 +95,7 @@ def __iter__(self): self.always_aslist) -class RapidXml(DictNode, _rapidxml.Document): +class RapidXml(DictNode, rapidxml.c_ext.Document): def __init__(self, text="", from_file=False, @@ -102,7 +103,7 @@ def __init__(self, cdata_key='#text', always_aslist=False): DictNode.__init__(self, attribute_prefix, cdata_key, always_aslist) - _rapidxml.Document.__init__(self, text, from_file) + rapidxml.c_ext.Document.__init__(self, text, from_file) def allocate_node(self, *args): return DictNode(self.attribute_prefix, diff --git a/setup.py b/setup.py index 82a247d..a44a555 100644 --- a/setup.py +++ b/setup.py @@ -8,9 +8,9 @@ from setuptools import setup, Extension, find_packages -VERSION = ("1", "0", "7") +VERSION = ("2", "0", "0") -rapidxml = Extension("_rapidxml", +rapidxml = Extension("rapidxml.c_ext", define_macros=[('MAJOR_VERSION', VERSION[0]), ('MINOR_VERSION', VERSION[1])], include_dirs=[ From 8f69da3e5f02202895286def9bab6cfa87b12f3c Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Wed, 20 May 2015 02:07:34 +0900 Subject: [PATCH 073/101] using Py_buffer to allow all type of data, instead just bytearray & add flag raw to unparse --- rapidxml/c_ext/src/base_object.cpp | 70 ++++++++++---------- rapidxml/c_ext/src/common.cpp | 8 ++- rapidxml/c_ext/src/document_object.cpp | 90 ++++++++++++++------------ rapidxml/c_ext/src/node_object.cpp | 23 +++++-- 4 files changed, 110 insertions(+), 81 deletions(-) diff --git a/rapidxml/c_ext/src/base_object.cpp b/rapidxml/c_ext/src/base_object.cpp index b006146..3792614 100644 --- a/rapidxml/c_ext/src/base_object.cpp +++ b/rapidxml/c_ext/src/base_object.cpp @@ -86,17 +86,28 @@ static PyObject* rapidxml_BaseObject_richcmp(PyObject* obj1, } static PyObject* rapidxml_BaseObject_getname(rapidxml_BaseObject* self, - void* closure) { + void* closure) { + PyObject* res; + if (self->underlying_obj == NULL) { - return Py_BuildValue("s", ""); + res = Py_BuildValue("s", ""); + } else { + res = Py_BuildValue("s", self->underlying_obj->name()); +#if PY_MAJOR_VERSION >= 3 + if (res == NULL && PyErr_Occurred()) { + res = Py_BuildValue("y", + self->underlying_obj->name(), + self->underlying_obj->name_size()); + } +#endif } - return Py_BuildValue("s", self->underlying_obj->name()); + return res; } static int rapidxml_BaseObject_setname(rapidxml_BaseObject* self, PyObject* arg, void* closure) { - const char* name; + Py_buffer name; if (self->underlying_obj == NULL || self->document == NULL) { PyErr_SetString(rapidxml_RapidXmlError, @@ -105,39 +116,39 @@ static int rapidxml_BaseObject_setname(rapidxml_BaseObject* self, } if (arg == NULL) { PyErr_SetString(PyExc_TypeError, - "name attribute must not be null"); - return -1; - } - if (! -#if PY_MAJOR_VERSION >= 3 - PyUnicode_Check(arg) -#else - PyString_Check(arg) -#endif - ) { - PyErr_SetString(PyExc_TypeError, - "name attribute must be a string"); + "Cannot delete name"); return -1; } - if (!PyArg_Parse(arg, "s", &name)) { + if (!PyArg_Parse(arg, "s*", &name)) { return -1; } - self->underlying_obj->name(self->document->allocate_string(name)); + self->underlying_obj->name(self->document->allocate_string(static_cast(name.buf))); return 0; } static PyObject* rapidxml_BaseObject_getvalue(rapidxml_BaseObject* self, void* closure) { + PyObject* res; + if (self->underlying_obj == NULL) { - return Py_BuildValue("s", ""); + res = Py_BuildValue("s", ""); + } else { + res = Py_BuildValue("s", self->underlying_obj->value()); +#if PY_MAJOR_VERSION >= 3 + if (res == NULL && PyErr_Occurred()) { + res = Py_BuildValue("y", + self->underlying_obj->value(), + self->underlying_obj->value_size()); + } +#endif } - return Py_BuildValue("s", self->underlying_obj->value()); + return res; } static int rapidxml_BaseObject_setvalue(rapidxml_BaseObject* self, PyObject* arg, void* closure) { - const char* value; + Py_buffer value; if (self->underlying_obj == NULL || self->document == NULL) { PyErr_SetString(rapidxml_RapidXmlError, @@ -146,24 +157,13 @@ static int rapidxml_BaseObject_setvalue(rapidxml_BaseObject* self, } if (arg == NULL) { PyErr_SetString(PyExc_TypeError, - "value attribute must not be null"); - return -1; - } - if (! -#if PY_MAJOR_VERSION >= 3 - PyUnicode_Check(arg) -#else - PyString_Check(arg) -#endif - ) { - PyErr_SetString(PyExc_TypeError, - "value attribute must be a string"); + "Cannot delete value"); return -1; } - if (!PyArg_Parse(arg, "s", &value)) { + if (!PyArg_Parse(arg, "s*", &value)) { return -1; } - self->underlying_obj->value(self->document->allocate_string(value)); + self->underlying_obj->value(self->document->allocate_string(static_cast(value.buf))); return 0; } diff --git a/rapidxml/c_ext/src/common.cpp b/rapidxml/c_ext/src/common.cpp index 154272b..fc74fc5 100644 --- a/rapidxml/c_ext/src/common.cpp +++ b/rapidxml/c_ext/src/common.cpp @@ -17,12 +17,16 @@ int _parse_args_for_name(PyObject* args, PyObject* kwds, const char** name) { char kw_name[] = "name"; + Py_buffer buf = {0}; static char* kwlist[] = {kw_name, NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist, - name)) { + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s*", kwlist, + &buf)) { return false; } + if (buf.buf) { + *name = static_cast(buf.buf); + } return true; } diff --git a/rapidxml/c_ext/src/document_object.cpp b/rapidxml/c_ext/src/document_object.cpp index 80669be..87decce 100644 --- a/rapidxml/c_ext/src/document_object.cpp +++ b/rapidxml/c_ext/src/document_object.cpp @@ -23,42 +23,23 @@ static void rapidxml_DocumentObject_dealloc(rapidxml_DocumentObject* self) { Py_TYPE(self)->tp_free(reinterpret_cast(self)); } -static PyObject* rapidxml_DocumentObject_parse(rapidxml_DocumentObject* self, - PyObject* args, - PyObject* kwds) { - const char* text = NULL; - PyObject* text_obj = NULL; - PyObject* from_file_obj = NULL; - char kw_text[] = "text"; - char kw_from_file[] = "from_file"; +static int _parse(rapidxml_DocumentObject* self, + Py_buffer* text_buff, + bool from_file) { + const char* text; std::vector text_vector; - static char* kwlist[] = {kw_text, kw_from_file, NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, - &text_obj, &from_file_obj)) { - return NULL; - } - - if ((from_file_obj != NULL) && PyObject_IsTrue(from_file_obj)) { - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|O", kwlist, - &text, &from_file_obj)) { - return NULL; - } + text = static_cast(text_buff->buf); + if (from_file) { std::ifstream f(text, std::ios::binary); if (f.fail()) { PyErr_SetString(rapidxml_RapidXmlError, strerror(errno)); - return NULL; + return 0; } text_vector = std::vector((std::istreambuf_iterator(f)), std::istreambuf_iterator()); text_vector.push_back(0); text = &text_vector[0]; - } else { - if (!PyByteArray_Check(text_obj)) { - PyErr_SetString(PyExc_TypeError, "argument 1 must be bytearray"); - return NULL; - } - text = PyByteArray_AsString(text_obj); } try { self->base.base.document->clear(); @@ -67,6 +48,27 @@ static PyObject* rapidxml_DocumentObject_parse(rapidxml_DocumentObject* self, (self->base.base.document->allocate_string(text)); } catch (rapidxml::parse_error &e) { PyErr_SetString(rapidxml_RapidXmlError, e.what()); + return 0; + } + return 1; +} + +static PyObject* rapidxml_DocumentObject_parse(rapidxml_DocumentObject* self, + PyObject* args, + PyObject* kwds) { + Py_buffer text_buff; + PyObject* from_file_obj = NULL; + char kw_text[] = "text"; + char kw_from_file[] = "from_file"; + + static char* kwlist[] = {kw_text, kw_from_file, NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s*|O", kwlist, + &text_buff, &from_file_obj)) { + return NULL; + } + + if (!_parse(self, &text_buff, + (from_file_obj != NULL) && PyObject_IsTrue(from_file_obj))) { return NULL; } Py_INCREF(Py_None); @@ -76,7 +78,7 @@ static PyObject* rapidxml_DocumentObject_parse(rapidxml_DocumentObject* self, static int rapidxml_DocumentObject_init(rapidxml_DocumentObject* self, PyObject* args, PyObject* kwds) { - PyObject* text_obj = NULL; + Py_buffer text_buff = {0}; PyObject* from_file_obj = NULL; char kw_text[] = "text"; char kw_from_file[] = "from_file"; @@ -85,14 +87,14 @@ static int rapidxml_DocumentObject_init(rapidxml_DocumentObject* self, return -1; } static char* kwlist[] = {kw_text, kw_from_file, NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist, - &text_obj, &from_file_obj)) { + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s*O", kwlist, + &text_buff, &from_file_obj)) { return -1; } self->base.base.underlying_obj = new rapidxml::xml_document<>(); self->base.base.document = static_cast*>(self->base.base.underlying_obj); - if (text_obj && PyObject_IsTrue(text_obj)) { - rapidxml_DocumentObject_parse(self, args, kwds); + if (text_buff.buf) { + return _parse(self, &text_buff, (from_file_obj != NULL) && PyObject_IsTrue(from_file_obj)) - 1; } return 0; } @@ -100,21 +102,25 @@ static int rapidxml_DocumentObject_init(rapidxml_DocumentObject* self, static PyObject* rapidxml_DocumentObject_allocate_node(rapidxml_DocumentObject* self, PyObject* args, PyObject* kwds) { - const char* name = NULL; - const char* value = NULL; + const char* name; + Py_buffer name_buff = {0}; + const char* value; + Py_buffer value_buff = {0}; char kw_name[] = "name"; char kw_value[] = "value"; rapidxml::xml_node<>* node; static char* kwlist[] = {kw_name, kw_value, NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ss", kwlist, - &name, &value)) { + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s*s*", kwlist, + &name_buff, &value_buff)) { Py_INCREF(Py_None); return Py_None; } + name = static_cast(name_buff.buf); if (name) { name = self->base.base.document->allocate_string(name); } + value = static_cast(value_buff.buf); if (value) { value = self->base.base.document->allocate_string(value); } @@ -122,25 +128,29 @@ static PyObject* rapidxml_DocumentObject_allocate_node(rapidxml_DocumentObject* return _bind_result(reinterpret_cast(self), node, &rapidxml_NodeType); } - +#include static PyObject* rapidxml_DocumentObject_allocate_attribute(rapidxml_DocumentObject* self, PyObject* args, PyObject* kwds) { - const char* name = NULL; - const char* value = NULL; + const char* name; + Py_buffer name_buff = {0}; + const char* value; + Py_buffer value_buff = {0}; char kw_name[] = "name"; char kw_value[] = "value"; rapidxml::xml_attribute<>* attribute; static char* kwlist[] = {kw_name, kw_value, NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ss", kwlist, - &name, &value)) { + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s*s*", kwlist, + &name_buff, &value_buff)) { Py_INCREF(Py_None); return Py_None; } + name = static_cast(name_buff.buf); if (name) { name = self->base.base.document->allocate_string(name); } + value = static_cast(value_buff.buf); if (value) { value = self->base.base.document->allocate_string(value); } diff --git a/rapidxml/c_ext/src/node_object.cpp b/rapidxml/c_ext/src/node_object.cpp index a5ff191..ea147db 100644 --- a/rapidxml/c_ext/src/node_object.cpp +++ b/rapidxml/c_ext/src/node_object.cpp @@ -405,17 +405,32 @@ static PyObject* rapidxml_NodeObject_unparse(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { PyObject* pretty_obj = NULL; + PyObject* raw_obj = NULL; + PyObject* res; std::string xml; char kw_pretty[] = "pretty"; + char kw_raw[] = "raw"; - static char* kwlist[] = {kw_pretty, NULL}; - PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &pretty_obj); + static char* kwlist[] = {kw_pretty, kw_raw, NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist, + &pretty_obj, &raw_obj)) { + return NULL; + } rapidxml::print(std::back_inserter(xml), *(static_cast*>(self->base.underlying_obj)), ((pretty_obj == NULL) || PyObject_Not(pretty_obj)) ? rapidxml::print_no_indenting : 0); - return Py_BuildValue("s", xml.c_str()); + if ((raw_obj == NULL) || PyObject_Not(raw_obj) +#if PY_MAJOR_VERSION < 3 + || true +#endif + ) { + res = Py_BuildValue("s", xml.c_str()); + } else { + res = Py_BuildValue("y", xml.c_str(), xml.length()); + } + return res; } static PyObject* rapidxml_NodeObject___str__(rapidxml_NodeObject* self) { @@ -432,7 +447,7 @@ static PyObject* rapidxml_NodeObject___repr__(rapidxml_NodeObject* self) { PyObject* args; PyObject* res; - args = Py_BuildValue("(O)", Py_False); + args = Py_BuildValue("()"); res = rapidxml_NodeObject_unparse(self, args, NULL); Py_DECREF(args); return res; From 422aa684bf628abf7bc71e3ee60392a4f983996f Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Wed, 20 May 2015 02:07:56 +0900 Subject: [PATCH 074/101] adding some tests --- README.md | 9 +++++---- tests/conftest.py | 4 ++-- tests/test_attributes.py | 32 ++++++++++++++++++++++++++++++++ tests/test_basic.py | 2 +- tests/test_utf8.py | 21 +++++++++++++++++++++ 5 files changed, 61 insertions(+), 7 deletions(-) create mode 100644 tests/test_utf8.py diff --git a/README.md b/README.md index 925fe3b..0301cae 100644 --- a/README.md +++ b/README.md @@ -6,20 +6,21 @@ A library providing python bindings for rapidxml import rapidxml - r = rapidxml.RapidXml("foo") # parsing from string + r = rapidxml.RapidXml(b"foo") # parsing from bytes test = r.first_node("test") # get first node named test test.name = "foo" # changing node's name to foo r.first_node("test2").value = "bar" # changing node's value to bar - print(str(r)) # will output prettified string of the xml document + print(str(r)) # will output a prettified string of the xml document + print(r.unparse(pretty=False, raw=True)) # will output the xml document as flat bytes print(test) # also works for nodes with open('dump.xml', 'w') as f: f.write(str(r)) r = rapidxml.RapidXml("dump.xml", True) # loading from file - assert(str(r) == r.unparse(True)) # is always True - assert(repr(r) == r.unparse()) # also always True, returns flat version + assert(str(r) == r.unparse(True, False)) # is always True + assert(repr(r) == r.unparse(pretty=False, raw=False)) # also always True ### Install diff --git a/tests/conftest.py b/tests/conftest.py index fa9ffd7..1b69509 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -11,7 +11,7 @@ @pytest.fixture(scope="function") def init_rapidxml(): - r = rapidxml.RapidXml(bytearray(b""" + r = rapidxml.RapidXml(b""" @@ -20,5 +20,5 @@ def init_rapidxml(): some text -""")) +""") return r diff --git a/tests/test_attributes.py b/tests/test_attributes.py index a761ea4..6f41ad0 100644 --- a/tests/test_attributes.py +++ b/tests/test_attributes.py @@ -21,3 +21,35 @@ def test_last_attribute(init_rapidxml): attr2 = test.last_attribute("attr2") assert attr2.name == "attr2" assert attr2.value == "two" + +def test_append_attribute(init_rapidxml): + root = init_rapidxml.first_node() + root.append_attribute(init_rapidxml.allocate_attribute()) + assert root.last_attribute().name == "" + assert root.last_attribute().value == "" + root.append_attribute(init_rapidxml.allocate_attribute("test")) + assert root.last_attribute().name == "test" + assert root.last_attribute().value == "" + root.append_attribute(init_rapidxml.allocate_attribute(value="test")) + assert root.last_attribute().name == "" + assert root.last_attribute().value == "test" + root.append_attribute(init_rapidxml.allocate_attribute("test", "test")) + assert root.last_attribute().name == "test" + assert root.last_attribute().value == "test" + +def test_prepend_attribute(init_rapidxml): + root = init_rapidxml.first_node() + root.prepend_attribute(init_rapidxml.allocate_attribute("test", "test")) + assert root.first_attribute().name == "test" + assert root.first_attribute().value == "test" + root.prepend_attribute(init_rapidxml.allocate_attribute("test2", "test2")) + assert root.first_attribute().name == "test2" + assert root.first_attribute().value == "test2" + +def test_insert_attribute(init_rapidxml): + test = init_rapidxml.first_node().first_node() + attr2 = test.first_attribute("attr2") + test.insert_attribute(attr2, init_rapidxml.allocate_attribute("test", "test")) + test = attr2.previous_attribute() + assert test.name == "test" + assert test.value == "test" diff --git a/tests/test_basic.py b/tests/test_basic.py index fcbc1fa..1fea09b 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -22,7 +22,7 @@ def test_parse(init_rapidxml): data = init_rapidxml.unparse().encode('utf-8') except UnicodeDecodeError: data = init_rapidxml.unparse() - r.parse(bytearray(data)) + r.parse(data) assert str(r) == str(init_rapidxml) def test_parse_from_file(init_rapidxml, tmpdir): diff --git a/tests/test_utf8.py b/tests/test_utf8.py new file mode 100644 index 0000000..957d173 --- /dev/null +++ b/tests/test_utf8.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# File: test_utf8.py +# by Arzaroth Lekva +# arzaroth@arzaroth.com +# + +import sys +import rapidxml + +def test_utf8(): + data = "éè" + if sys.version_info.major >= 3: + data = data.encode('utf-8') + r = rapidxml.RapidXml(data) + assert str(r) == r.unparse(pretty=True) + assert repr(r) == r.unparse() + assert data == r.unparse(raw=True) + r.first_node().value = b'\x85' + assert r.unparse(raw=True).decode('cp1252').encode('utf-8') == b"\xe2\x80\xa6" From da871f1be640d32eaa073e8e639a5d9730422d2a Mon Sep 17 00:00:00 2001 From: Marc-Etienne Barrut Date: Wed, 20 May 2015 02:41:27 +0900 Subject: [PATCH 075/101] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0301cae..293188a 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,6 @@ MIT license. See the LICENSE file. ### Development status -[![Build Status](https://travis-ci.org/Arzaroth/python_rapidxml.svg?branch=1.0)](https://travis-ci.org/Arzaroth/python_rapidxml) +[![Build Status](https://travis-ci.org/Arzaroth/python_rapidxml.svg?branch=2.0)](https://travis-ci.org/Arzaroth/python_rapidxml) This project is currently under development. From 61399b59bd70e9db3ffaaa225eed32770da17dd2 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Wed, 20 May 2015 02:43:06 +0900 Subject: [PATCH 076/101] patched a test for python2.6 --- tests/test_utf8.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_utf8.py b/tests/test_utf8.py index 957d173..5512459 100644 --- a/tests/test_utf8.py +++ b/tests/test_utf8.py @@ -11,7 +11,7 @@ def test_utf8(): data = "éè" - if sys.version_info.major >= 3: + if sys.version_info[0] >= 3: data = data.encode('utf-8') r = rapidxml.RapidXml(data) assert str(r) == r.unparse(pretty=True) From 38ce6c2d5eb02b7f7e33caaa8e780b2652d1d711 Mon Sep 17 00:00:00 2001 From: "Amedeo BUSSI (contractor)" Date: Mon, 22 May 2017 16:54:36 +0200 Subject: [PATCH 077/101] cdata decodoing --- rapidxml/c_ext/src/document_object.cpp | 28 +++++++++++++++++--------- rapidxml/rapidxml.py | 5 +++-- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/rapidxml/c_ext/src/document_object.cpp b/rapidxml/c_ext/src/document_object.cpp index 87decce..b1ab406 100644 --- a/rapidxml/c_ext/src/document_object.cpp +++ b/rapidxml/c_ext/src/document_object.cpp @@ -25,7 +25,7 @@ static void rapidxml_DocumentObject_dealloc(rapidxml_DocumentObject* self) { static int _parse(rapidxml_DocumentObject* self, Py_buffer* text_buff, - bool from_file) { + bool from_file, bool parse_cdata=false) { const char* text; std::vector text_vector; @@ -43,9 +43,17 @@ static int _parse(rapidxml_DocumentObject* self, } try { self->base.base.document->clear(); - (self->base.base.document - ->parse) - (self->base.base.document->allocate_string(text)); + if (parse_cdata){ + (self->base.base.document + ->parse) + (self->base.base.document->allocate_string(text)); + + }else{ + (self->base.base.document + ->parse) + (self->base.base.document->allocate_string(text)); + } + } catch (rapidxml::parse_error &e) { PyErr_SetString(rapidxml_RapidXmlError, e.what()); return 0; @@ -58,17 +66,19 @@ static PyObject* rapidxml_DocumentObject_parse(rapidxml_DocumentObject* self, PyObject* kwds) { Py_buffer text_buff; PyObject* from_file_obj = NULL; - char kw_text[] = "text"; + bool read_cdata = false + char kw_text[] = "text char kw_from_file[] = "from_file"; + char kw_parse_cdata[] = "parse_cdata"; - static char* kwlist[] = {kw_text, kw_from_file, NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s*|O", kwlist, - &text_buff, &from_file_obj)) { + static char* kwlist[] = {kw_text, kw_from_file, kw_parse_cdata, NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s*|Op", kwlist, + &text_buff, &from_file_obj, &read_cdata)) { return NULL; } if (!_parse(self, &text_buff, - (from_file_obj != NULL) && PyObject_IsTrue(from_file_obj))) { + (from_file_obj != NULL) && PyObject_IsTrue(from_file_obj), read_cdata)) { return NULL; } Py_INCREF(Py_None); diff --git a/rapidxml/rapidxml.py b/rapidxml/rapidxml.py index 268529d..77cffae 100644 --- a/rapidxml/rapidxml.py +++ b/rapidxml/rapidxml.py @@ -101,9 +101,10 @@ def __init__(self, from_file=False, attribute_prefix='@', cdata_key='#text', - always_aslist=False): + always_aslist=False, + parse_cdata=False): DictNode.__init__(self, attribute_prefix, cdata_key, always_aslist) - rapidxml.c_ext.Document.__init__(self, text, from_file) + rapidxml.c_ext.Document.__init__(self, text, from_file, parse_cdata) def allocate_node(self, *args): return DictNode(self.attribute_prefix, From c71bb9cdcb30a76139e69e0bc72134b22f92df76 Mon Sep 17 00:00:00 2001 From: "Amedeo BUSSI (contractor)" Date: Mon, 22 May 2017 16:58:54 +0200 Subject: [PATCH 078/101] cdata decodoing --- rapidxml/c_ext/src/document_object.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rapidxml/c_ext/src/document_object.cpp b/rapidxml/c_ext/src/document_object.cpp index b1ab406..5a2c7a3 100644 --- a/rapidxml/c_ext/src/document_object.cpp +++ b/rapidxml/c_ext/src/document_object.cpp @@ -67,7 +67,7 @@ static PyObject* rapidxml_DocumentObject_parse(rapidxml_DocumentObject* self, Py_buffer text_buff; PyObject* from_file_obj = NULL; bool read_cdata = false - char kw_text[] = "text + char kw_text[] = "text" char kw_from_file[] = "from_file"; char kw_parse_cdata[] = "parse_cdata"; From ee5a754454711d55ed56f2a27faae485f3448013 Mon Sep 17 00:00:00 2001 From: "Amedeo BUSSI (contractor)" Date: Mon, 22 May 2017 17:02:42 +0200 Subject: [PATCH 079/101] cdata decodoing --- rapidxml/c_ext/src/document_object.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/rapidxml/c_ext/src/document_object.cpp b/rapidxml/c_ext/src/document_object.cpp index 5a2c7a3..24ed31f 100644 --- a/rapidxml/c_ext/src/document_object.cpp +++ b/rapidxml/c_ext/src/document_object.cpp @@ -67,7 +67,7 @@ static PyObject* rapidxml_DocumentObject_parse(rapidxml_DocumentObject* self, Py_buffer text_buff; PyObject* from_file_obj = NULL; bool read_cdata = false - char kw_text[] = "text" + char kw_text[] = "text"; char kw_from_file[] = "from_file"; char kw_parse_cdata[] = "parse_cdata"; @@ -92,19 +92,20 @@ static int rapidxml_DocumentObject_init(rapidxml_DocumentObject* self, PyObject* from_file_obj = NULL; char kw_text[] = "text"; char kw_from_file[] = "from_file"; + char kw_parse_cdata[] = "parse_cdata"; if (rapidxml_NodeType.tp_init(reinterpret_cast(self), args, kwds) < 0) { return -1; } - static char* kwlist[] = {kw_text, kw_from_file, NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s*O", kwlist, - &text_buff, &from_file_obj)) { + static char* kwlist[] = {kw_text, kw_from_file, kw_parse_cdata, NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s*Op", kwlist, + &text_buff, &from_file_obj, &read_cdata)) { return -1; } self->base.base.underlying_obj = new rapidxml::xml_document<>(); self->base.base.document = static_cast*>(self->base.base.underlying_obj); if (text_buff.buf) { - return _parse(self, &text_buff, (from_file_obj != NULL) && PyObject_IsTrue(from_file_obj)) - 1; + return _parse(self, &text_buff, (from_file_obj != NULL) && PyObject_IsTrue(from_file_obj), read_cdata) - 1; } return 0; } From 31ff910f4995f85384f43580e7a51e022d1688dd Mon Sep 17 00:00:00 2001 From: "Amedeo BUSSI (contractor)" Date: Mon, 22 May 2017 17:18:33 +0200 Subject: [PATCH 080/101] cdata decodoing --- rapidxml/c_ext/src/document_object.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/rapidxml/c_ext/src/document_object.cpp b/rapidxml/c_ext/src/document_object.cpp index 24ed31f..a87bc60 100644 --- a/rapidxml/c_ext/src/document_object.cpp +++ b/rapidxml/c_ext/src/document_object.cpp @@ -90,6 +90,7 @@ static int rapidxml_DocumentObject_init(rapidxml_DocumentObject* self, PyObject* kwds) { Py_buffer text_buff = {0}; PyObject* from_file_obj = NULL; + bool read_cdata = false char kw_text[] = "text"; char kw_from_file[] = "from_file"; char kw_parse_cdata[] = "parse_cdata"; From 58a0ff3ee1ec7dc4a0acf9014a285d3568e3541e Mon Sep 17 00:00:00 2001 From: "Amedeo BUSSI (contractor)" Date: Mon, 22 May 2017 17:22:41 +0200 Subject: [PATCH 081/101] cdata decodoing --- rapidxml/c_ext/src/document_object.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rapidxml/c_ext/src/document_object.cpp b/rapidxml/c_ext/src/document_object.cpp index a87bc60..d217552 100644 --- a/rapidxml/c_ext/src/document_object.cpp +++ b/rapidxml/c_ext/src/document_object.cpp @@ -66,7 +66,7 @@ static PyObject* rapidxml_DocumentObject_parse(rapidxml_DocumentObject* self, PyObject* kwds) { Py_buffer text_buff; PyObject* from_file_obj = NULL; - bool read_cdata = false + bool read_cdata = false; char kw_text[] = "text"; char kw_from_file[] = "from_file"; char kw_parse_cdata[] = "parse_cdata"; @@ -90,7 +90,7 @@ static int rapidxml_DocumentObject_init(rapidxml_DocumentObject* self, PyObject* kwds) { Py_buffer text_buff = {0}; PyObject* from_file_obj = NULL; - bool read_cdata = false + bool read_cdata = false; char kw_text[] = "text"; char kw_from_file[] = "from_file"; char kw_parse_cdata[] = "parse_cdata"; From 41e9a8f0e728c90f0863605d4b993244c3aafbee Mon Sep 17 00:00:00 2001 From: "Amedeo BUSSI (contractor)" Date: Mon, 22 May 2017 17:37:30 +0200 Subject: [PATCH 082/101] cdata test --- rapidxml/c_ext/src/document_object.cpp | 2 +- tests/test_cdata.py | 40 ++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 tests/test_cdata.py diff --git a/rapidxml/c_ext/src/document_object.cpp b/rapidxml/c_ext/src/document_object.cpp index d217552..ba55447 100644 --- a/rapidxml/c_ext/src/document_object.cpp +++ b/rapidxml/c_ext/src/document_object.cpp @@ -43,7 +43,7 @@ static int _parse(rapidxml_DocumentObject* self, } try { self->base.base.document->clear(); - if (parse_cdata){ + if (!parse_cdata){ (self->base.base.document ->parse) (self->base.base.document->allocate_string(text)); diff --git a/tests/test_cdata.py b/tests/test_cdata.py new file mode 100644 index 0000000..cc6dd5f --- /dev/null +++ b/tests/test_cdata.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# -*- encoding: cdata -*- +# +# File: test_cdata.py +# by Amedeo Bussi +# amedeobussi@live.it +# + +import sys +import rapidxml +import json + +def test_utf8(): + data = "" + + object = \ + { + "Cart": + { + "expirationTime":"2017-04-22T09:40", + "id":"b469df3b-f626-4fe3-898c-825373e546a2", + "products":["1223"], + "creationTime":"2017-04-21T09:40", + "totalPrice": + { + "currencyCode":"EUR", + "amount":"138.000" + } + } + } + + print("Expected cdata object: " + str(object)) + + r = rapidxml.RapidXml(data) + + object_received = json.load(r.first_node().first_node().first_node().value) + + print("Expected cdata object: " + str(object_received)) + + assert object_received == object \ No newline at end of file From ed29622ac15ccdc2b0480b368f082ee9046e8f09 Mon Sep 17 00:00:00 2001 From: "Amedeo BUSSI (contractor)" Date: Mon, 22 May 2017 17:50:48 +0200 Subject: [PATCH 083/101] test update --- tests/test_cdata.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tests/test_cdata.py b/tests/test_cdata.py index cc6dd5f..279333c 100644 --- a/tests/test_cdata.py +++ b/tests/test_cdata.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# -*- encoding: cdata -*- +# -*- encoding: utf-8 -*- # # File: test_cdata.py # by Amedeo Bussi @@ -8,9 +8,8 @@ import sys import rapidxml -import json -def test_utf8(): +def test_cdata(): data = "" object = \ @@ -31,10 +30,17 @@ def test_utf8(): print("Expected cdata object: " + str(object)) - r = rapidxml.RapidXml(data) + r = rapidxml.RapidXml(data, + from_file=False, + attribute_prefix='@', + cdata_key='#text', + always_aslist=False, + parse_cdata=True) - object_received = json.load(r.first_node().first_node().first_node().value) + print("Cdata object: " + str(r.first_node().first_node().first_node().value)) - print("Expected cdata object: " + str(object_received)) + #object_received = json.load(r.first_node().first_node().first_node().value) - assert object_received == object \ No newline at end of file + #print("Cdata object: " + str(object_received)) + + #assert object_received == object \ No newline at end of file From af8e1625ef89767cd93995d61096486582603462 Mon Sep 17 00:00:00 2001 From: "Amedeo BUSSI (contractor)" Date: Mon, 22 May 2017 17:54:04 +0200 Subject: [PATCH 084/101] adding assertion --- tests/test_cdata.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/test_cdata.py b/tests/test_cdata.py index 279333c..54f6f57 100644 --- a/tests/test_cdata.py +++ b/tests/test_cdata.py @@ -8,6 +8,7 @@ import sys import rapidxml +import ast def test_cdata(): data = "" @@ -27,8 +28,6 @@ def test_cdata(): } } } - - print("Expected cdata object: " + str(object)) r = rapidxml.RapidXml(data, from_file=False, @@ -37,10 +36,8 @@ def test_cdata(): always_aslist=False, parse_cdata=True) - print("Cdata object: " + str(r.first_node().first_node().first_node().value)) + object_received = ast.literal_eval(r.first_node().first_node().first_node().value) - #object_received = json.load(r.first_node().first_node().first_node().value) + print("Cdata object: " + str(object_received)) - #print("Cdata object: " + str(object_received)) - - #assert object_received == object \ No newline at end of file + assert object_received == object \ No newline at end of file From 52f4715b66d3aca9438a6d345c6ca84bd6ab8950 Mon Sep 17 00:00:00 2001 From: "Amedeo BUSSI (contractor)" Date: Mon, 22 May 2017 17:56:35 +0200 Subject: [PATCH 085/101] test update --- tests/test_cdata.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test_cdata.py b/tests/test_cdata.py index 54f6f57..56e1bfc 100644 --- a/tests/test_cdata.py +++ b/tests/test_cdata.py @@ -38,6 +38,4 @@ def test_cdata(): object_received = ast.literal_eval(r.first_node().first_node().first_node().value) - print("Cdata object: " + str(object_received)) - assert object_received == object \ No newline at end of file From 007e59f482ad18a5485a47e9a3f31f3f8734a058 Mon Sep 17 00:00:00 2001 From: "Amedeo BUSSI (contractor)" Date: Mon, 22 May 2017 18:46:30 +0200 Subject: [PATCH 086/101] python2 compatible --- rapidxml/c_ext/src/document_object.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/rapidxml/c_ext/src/document_object.cpp b/rapidxml/c_ext/src/document_object.cpp index ba55447..4257d32 100644 --- a/rapidxml/c_ext/src/document_object.cpp +++ b/rapidxml/c_ext/src/document_object.cpp @@ -66,19 +66,19 @@ static PyObject* rapidxml_DocumentObject_parse(rapidxml_DocumentObject* self, PyObject* kwds) { Py_buffer text_buff; PyObject* from_file_obj = NULL; - bool read_cdata = false; + PyObject* read_cdata = NULL; char kw_text[] = "text"; char kw_from_file[] = "from_file"; char kw_parse_cdata[] = "parse_cdata"; static char* kwlist[] = {kw_text, kw_from_file, kw_parse_cdata, NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s*|Op", kwlist, + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s*|OO", kwlist, &text_buff, &from_file_obj, &read_cdata)) { return NULL; } if (!_parse(self, &text_buff, - (from_file_obj != NULL) && PyObject_IsTrue(from_file_obj), read_cdata)) { + (from_file_obj != NULL) && PyObject_IsTrue(from_file_obj), (read_cdata != NULL) && PyObject_IsTrue(read_cdata))) { return NULL; } Py_INCREF(Py_None); @@ -90,7 +90,7 @@ static int rapidxml_DocumentObject_init(rapidxml_DocumentObject* self, PyObject* kwds) { Py_buffer text_buff = {0}; PyObject* from_file_obj = NULL; - bool read_cdata = false; + PyObject* read_cdata = NULL; char kw_text[] = "text"; char kw_from_file[] = "from_file"; char kw_parse_cdata[] = "parse_cdata"; @@ -99,14 +99,14 @@ static int rapidxml_DocumentObject_init(rapidxml_DocumentObject* self, return -1; } static char* kwlist[] = {kw_text, kw_from_file, kw_parse_cdata, NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s*Op", kwlist, + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s*OO", kwlist, &text_buff, &from_file_obj, &read_cdata)) { return -1; } self->base.base.underlying_obj = new rapidxml::xml_document<>(); self->base.base.document = static_cast*>(self->base.base.underlying_obj); if (text_buff.buf) { - return _parse(self, &text_buff, (from_file_obj != NULL) && PyObject_IsTrue(from_file_obj), read_cdata) - 1; + return _parse(self, &text_buff, (from_file_obj != NULL) && PyObject_IsTrue(from_file_obj), (read_cdata != NULL) && PyObject_IsTrue(read_cdata)) - 1; } return 0; } From 795e8ed2572300d14a097086f9ae0544a5165950 Mon Sep 17 00:00:00 2001 From: "Amedeo BUSSI (contractor)" Date: Tue, 23 May 2017 13:32:50 +0200 Subject: [PATCH 087/101] test on cdata fun --- rapidxml/rapidxml.py | 9 ++++++ tests/conftest.py | 11 ++++++++ tests/test_attributes.py | 48 +++++++++++++++++++++++++++++++ tests/test_basic.py | 61 ++++++++++++++++++++++++++++++++++++++++ tests/test_cdata.py | 5 +++- tests/test_iterations.py | 24 ++++++++++++++++ tests/test_nodes.py | 39 +++++++++++++++++++++++++ 7 files changed, 196 insertions(+), 1 deletion(-) diff --git a/rapidxml/rapidxml.py b/rapidxml/rapidxml.py index 77cffae..8a6b9ad 100644 --- a/rapidxml/rapidxml.py +++ b/rapidxml/rapidxml.py @@ -110,3 +110,12 @@ def allocate_node(self, *args): return DictNode(self.attribute_prefix, self.cdata_key, self.always_aslist).copy(super(RapidXml, self).allocate_node(*args)) + + def uparse(self, pretty=False, raw=False, parse_cdata=False): + if parse_cdata: + current_xml = input_xml.first_node() + value = current_xml.value + current_xml.uparse(pretty=False, raw=False, parse_cdata=True) + return value + else: + DictNode.uparse(pretty, raw) + diff --git a/tests/conftest.py b/tests/conftest.py index 1b69509..ffaa97c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -22,3 +22,14 @@ def init_rapidxml(): some text """) return r + +@pytest.fixture(scope="function") +def init_rapidxml_with_CDADA(): + datra_str = "some text" + r = rapidxml.RapidXml(datra_str, + from_file=False, + attribute_prefix='@', + cdata_key='#text', + always_aslist=False, + parse_cdata=True) + return r diff --git a/tests/test_attributes.py b/tests/test_attributes.py index 6f41ad0..3699f1f 100644 --- a/tests/test_attributes.py +++ b/tests/test_attributes.py @@ -53,3 +53,51 @@ def test_insert_attribute(init_rapidxml): test = attr2.previous_attribute() assert test.name == "test" assert test.value == "test" + +def test_first_attribute_cdata(init_rapidxml_with_CDADA): + test = init_rapidxml_with_CDADA.first_node().first_node("test") + assert test.first_attribute().name == "attr1" + assert test.first_attribute().value == "one" + attr2 = test.first_attribute("attr2") + assert attr2.name == "attr2" + assert attr2.value == "two" + +def test_last_attribute_cdata(init_rapidxml_with_CDADA): + test = init_rapidxml_with_CDADA.first_node().first_node("test") + assert test.last_attribute().name == "attr3" + assert test.last_attribute().value == "three" + attr2 = test.last_attribute("attr2") + assert attr2.name == "attr2" + assert attr2.value == "two" + +def test_append_attribute_cdata(init_rapidxml_with_CDADA): + root = init_rapidxml_with_CDADA.first_node() + root.append_attribute(init_rapidxml_with_CDADA.allocate_attribute()) + assert root.last_attribute().name == "" + assert root.last_attribute().value == "" + root.append_attribute(init_rapidxml_with_CDADA.allocate_attribute("test")) + assert root.last_attribute().name == "test" + assert root.last_attribute().value == "" + root.append_attribute(init_rapidxml_with_CDADA.allocate_attribute(value="test")) + assert root.last_attribute().name == "" + assert root.last_attribute().value == "test" + root.append_attribute(init_rapidxml_with_CDADA.allocate_attribute("test", "test")) + assert root.last_attribute().name == "test" + assert root.last_attribute().value == "test" + +def test_prepend_attribute_cdata(init_rapidxml_with_CDADA): + root = init_rapidxml_with_CDADA.first_node() + root.prepend_attribute(init_rapidxml_with_CDADA.allocate_attribute("test", "test")) + assert root.first_attribute().name == "test" + assert root.first_attribute().value == "test" + root.prepend_attribute(init_rapidxml_with_CDADA.allocate_attribute("test2", "test2")) + assert root.first_attribute().name == "test2" + assert root.first_attribute().value == "test2" + +def test_insert_attribute_cdata(init_rapidxml_with_CDADA): + test = init_rapidxml_with_CDADA.first_node().first_node() + attr2 = test.first_attribute("attr2") + test.insert_attribute(attr2, init_rapidxml_with_CDADA.allocate_attribute("test", "test")) + test = attr2.previous_attribute() + assert test.name == "test" + assert test.value == "test" diff --git a/tests/test_basic.py b/tests/test_basic.py index 1fea09b..e908ca0 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -57,3 +57,64 @@ def test_assign(init_rapidxml): assert init_rapidxml.unparse() == ('' '' 'some new text') + +def test_init_cdata(init_rapidxml_with_CDADA): + print(str(init_rapidxml_with_CDADA.unparse())) + datra_str =('' + '' + 'some text' + "" + "" + "") + assert init_rapidxml_with_CDADA.unparse() == rapidxml.RapidXml(datra_str, + from_file=False, + attribute_prefix='@', + cdata_key='#text', + always_aslist=False, + parse_cdata=True).unparse() + assert init_rapidxml_with_CDADA.unparse() == repr(init_rapidxml_with_CDADA) + assert init_rapidxml_with_CDADA.unparse(True) == str(init_rapidxml_with_CDADA) + +def test_parse_cdata(init_rapidxml_with_CDADA): + r = rapidxml.RapidXml() + try: + data = init_rapidxml_with_CDADA.unparse().encode('utf-8') + except UnicodeDecodeError: + data = init_rapidxml_with_CDADA.unparse() + r.parse(data, from_file=False, parse_cdata=True) + assert str(r) == str(init_rapidxml_with_CDADA) + +def test_parse_from_file_cdata(init_rapidxml_with_CDADA, tmpdir): + f = tmpdir.join("dump.xml") + f.write(init_rapidxml_with_CDADA.unparse()) + r = rapidxml.RapidXml(str(f), from_file=True, parse_cdata=True) + assert str(r) == str(init_rapidxml_with_CDADA) + +def test_equals_cdata(init_rapidxml_with_CDADA): + assert init_rapidxml_with_CDADA == init_rapidxml_with_CDADA + root = init_rapidxml_with_CDADA.first_node() + assert root == root + assert root == init_rapidxml_with_CDADA.first_node() + assert root.first_node() != root.first_node("test2") + assert (root != root) == (not (root == root)) + +def test_parent_cdata(init_rapidxml_with_CDADA): + assert init_rapidxml_with_CDADA.parent is None + assert init_rapidxml_with_CDADA.first_node().parent == init_rapidxml_with_CDADA + +def test_assign_cdata(init_rapidxml_with_CDADA): + root = init_rapidxml_with_CDADA.first_node() + root.name = "new_root" + assert root.name == "new_root" + test = root.first_node() + test.name = "new_test" + test.first_attribute().name = "new_attr1" + test.first_attribute().next_attribute().value = "new_two" + test = root.first_node("test") + test.value = "some new text" + assert test.value == "some new text" + print(str(init_rapidxml_with_CDADA.unparse(parse_cdata=True))) + diff --git a/tests/test_cdata.py b/tests/test_cdata.py index 56e1bfc..4aba0ea 100644 --- a/tests/test_cdata.py +++ b/tests/test_cdata.py @@ -38,4 +38,7 @@ def test_cdata(): object_received = ast.literal_eval(r.first_node().first_node().first_node().value) - assert object_received == object \ No newline at end of file + assert object_received == object + + + diff --git a/tests/test_iterations.py b/tests/test_iterations.py index fd38f9f..0a716ce 100644 --- a/tests/test_iterations.py +++ b/tests/test_iterations.py @@ -29,3 +29,27 @@ def test_attributes(init_rapidxml): i_attr = i_attr.next_attribute() if i_attr: assert i_attr.previous_attribute() == attr + +def test_children_cdata(init_rapidxml_with_CDADA): + test2 = init_rapidxml_with_CDADA.first_node().first_node("test2") + i_node = test2.first_node() + for node in test2.children: + assert i_node == node + assert node.name == "node" + assert node.value == "" + i_node = i_node.next_sibling() + if i_node: + assert i_node.previous_sibling() == node + +def test_attributes_cdata(init_rapidxml_with_CDADA): + test = init_rapidxml_with_CDADA.first_node().first_node() + i_attr = test.first_attribute() + for attr, expected_attr in zip(test.attributes, [('attr1', 'one'), + ('attr2', 'two'), + ('attr3', 'three')]): + assert i_attr == attr + assert (attr.name, attr.value) == expected_attr + assert (i_attr.name, i_attr.value) == expected_attr + i_attr = i_attr.next_attribute() + if i_attr: + assert i_attr.previous_attribute() == attr diff --git a/tests/test_nodes.py b/tests/test_nodes.py index 4efde16..9099091 100644 --- a/tests/test_nodes.py +++ b/tests/test_nodes.py @@ -6,6 +6,8 @@ # arzaroth@arzaroth.com # +import ast + def test_first_node(init_rapidxml): root = init_rapidxml.first_node() assert root.name == "root" @@ -27,3 +29,40 @@ def test_nested_node(init_rapidxml): test2 = init_rapidxml.first_node().first_node("test2") assert test2.name == "test2" assert test2.value == "" + +def test_first_node_cdata(init_rapidxml_with_CDADA): + root = init_rapidxml_with_CDADA.first_node() + assert root.name == "root" + assert root.value == "" + assert root.unparse() == init_rapidxml_with_CDADA.unparse() + assert root.first_node() == root.first_node("test") + assert root.first_node() != root.first_node("test2") + +def test_last_node_cdata(init_rapidxml_with_CDADA): + root = init_rapidxml_with_CDADA.first_node() + assert root.first_node() != root.last_node() + assert root.first_node("test2") == root.last_node("test2") + object = \ + { + "Cart": + { + "expirationTime":"2017-04-22T09:40", + "id":"b469df3b-f626-4fe3-898c-825373e546a2", + "products":["1223"], + "creationTime":"2017-04-21T09:40", + "totalPrice": + { + "currencyCode":"EUR", + "amount":"138.000" + } + } + } + assert ast.literal_eval(root.last_node().first_node().first_node().value) == object + +def test_nested_node_cdata(init_rapidxml_with_CDADA): + test = init_rapidxml_with_CDADA.first_node().first_node("test") + assert test.name == "test" + assert test.value == "" + test2 = init_rapidxml_with_CDADA.first_node().first_node("test2") + assert test2.name == "test2" + assert test2.value == "" From 38e0b36ccba308c18175211c61d4c5c7d1ed06f8 Mon Sep 17 00:00:00 2001 From: "Amedeo BUSSI (contractor)" Date: Tue, 23 May 2017 13:35:40 +0200 Subject: [PATCH 088/101] test on cdata fun --- rapidxml/rapidxml.py | 16 ++++++++-------- tests/test_basic.py | 1 - 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/rapidxml/rapidxml.py b/rapidxml/rapidxml.py index 8a6b9ad..afa83b0 100644 --- a/rapidxml/rapidxml.py +++ b/rapidxml/rapidxml.py @@ -94,6 +94,14 @@ def __iter__(self): self.cdata_key, self.always_aslist) + def uparse(self, pretty=False, raw=False, parse_cdata=False): + if parse_cdata: + current_xml = input_xml.first_node() + value = current_xml.value + current_xml.uparse(pretty=False, raw=False, parse_cdata=True) + return value + else: + DictNode.uparse(pretty, raw) + class RapidXml(DictNode, rapidxml.c_ext.Document): def __init__(self, @@ -111,11 +119,3 @@ def allocate_node(self, *args): self.cdata_key, self.always_aslist).copy(super(RapidXml, self).allocate_node(*args)) - def uparse(self, pretty=False, raw=False, parse_cdata=False): - if parse_cdata: - current_xml = input_xml.first_node() - value = current_xml.value + current_xml.uparse(pretty=False, raw=False, parse_cdata=True) - return value - else: - DictNode.uparse(pretty, raw) - diff --git a/tests/test_basic.py b/tests/test_basic.py index e908ca0..bfcc543 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -59,7 +59,6 @@ def test_assign(init_rapidxml): 'some new text') def test_init_cdata(init_rapidxml_with_CDADA): - print(str(init_rapidxml_with_CDADA.unparse())) datra_str =('' '' 'some text' From 94fc70bb70decd202c9ab6f38c975cda562a5ef1 Mon Sep 17 00:00:00 2001 From: "Amedeo BUSSI (contractor)" Date: Tue, 23 May 2017 13:40:53 +0200 Subject: [PATCH 089/101] test on cdata fun --- rapidxml/rapidxml.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rapidxml/rapidxml.py b/rapidxml/rapidxml.py index afa83b0..58ad6c1 100644 --- a/rapidxml/rapidxml.py +++ b/rapidxml/rapidxml.py @@ -94,13 +94,13 @@ def __iter__(self): self.cdata_key, self.always_aslist) - def uparse(self, pretty=False, raw=False, parse_cdata=False): + def unparse(self, pretty=False, raw=False, parse_cdata=False): if parse_cdata: current_xml = input_xml.first_node() - value = current_xml.value + current_xml.uparse(pretty=False, raw=False, parse_cdata=True) + value = current_xml.value + current_xml.unparse(pretty=False, raw=False, parse_cdata=True) return value else: - DictNode.uparse(pretty, raw) + DictNode.unparse(pretty, raw) class RapidXml(DictNode, rapidxml.c_ext.Document): From 50b58962d13a4a956261cfa8127b50b67d3c4714 Mon Sep 17 00:00:00 2001 From: "Amedeo BUSSI (contractor)" Date: Tue, 23 May 2017 13:46:05 +0200 Subject: [PATCH 090/101] test update --- rapidxml/rapidxml.py | 9 --------- tests/test_basic.py | 1 - 2 files changed, 10 deletions(-) diff --git a/rapidxml/rapidxml.py b/rapidxml/rapidxml.py index 58ad6c1..7f8d1c9 100644 --- a/rapidxml/rapidxml.py +++ b/rapidxml/rapidxml.py @@ -94,15 +94,6 @@ def __iter__(self): self.cdata_key, self.always_aslist) - def unparse(self, pretty=False, raw=False, parse_cdata=False): - if parse_cdata: - current_xml = input_xml.first_node() - value = current_xml.value + current_xml.unparse(pretty=False, raw=False, parse_cdata=True) - return value - else: - DictNode.unparse(pretty, raw) - - class RapidXml(DictNode, rapidxml.c_ext.Document): def __init__(self, text="", diff --git a/tests/test_basic.py b/tests/test_basic.py index bfcc543..3883915 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -115,5 +115,4 @@ def test_assign_cdata(init_rapidxml_with_CDADA): test = root.first_node("test") test.value = "some new text" assert test.value == "some new text" - print(str(init_rapidxml_with_CDADA.unparse(parse_cdata=True))) From 9781bc861cf2d41674f2c42a241d8c29888b4a0a Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Wed, 24 May 2017 10:31:19 +0200 Subject: [PATCH 091/101] 3.6 & unused include --- .travis.yml | 2 ++ rapidxml/c_ext/src/document_object.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7d66f9c..2adef32 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,8 @@ python: - "2.7" - "3.3" - "3.4" + - "3.5" + - "3.6" install: - pip install -r test-requirements.txt - python setup.py install diff --git a/rapidxml/c_ext/src/document_object.cpp b/rapidxml/c_ext/src/document_object.cpp index 87decce..27a59ae 100644 --- a/rapidxml/c_ext/src/document_object.cpp +++ b/rapidxml/c_ext/src/document_object.cpp @@ -128,7 +128,7 @@ static PyObject* rapidxml_DocumentObject_allocate_node(rapidxml_DocumentObject* return _bind_result(reinterpret_cast(self), node, &rapidxml_NodeType); } -#include + static PyObject* rapidxml_DocumentObject_allocate_attribute(rapidxml_DocumentObject* self, PyObject* args, PyObject* kwds) { From c1b21587e5e0906ce023ea430ae6a518fca28898 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Wed, 24 May 2017 11:42:56 +0200 Subject: [PATCH 092/101] finalize merge pr #4 --- rapidxml/c_ext/src/document_object.cpp | 30 ++++++++++-------- rapidxml/rapidxml.py | 3 +- tests/conftest.py | 26 ++++++++++----- tests/test_cdata.py | 44 -------------------------- tests/test_nodes.py | 21 ++---------- tests/test_utf8.py | 11 +++++++ 6 files changed, 49 insertions(+), 86 deletions(-) delete mode 100644 tests/test_cdata.py diff --git a/rapidxml/c_ext/src/document_object.cpp b/rapidxml/c_ext/src/document_object.cpp index 5ef097e..685ded0 100644 --- a/rapidxml/c_ext/src/document_object.cpp +++ b/rapidxml/c_ext/src/document_object.cpp @@ -25,7 +25,8 @@ static void rapidxml_DocumentObject_dealloc(rapidxml_DocumentObject* self) { static int _parse(rapidxml_DocumentObject* self, Py_buffer* text_buff, - bool from_file, bool parse_cdata=false) { + bool from_file, + bool parse_cdata) { const char* text; std::vector text_vector; @@ -43,17 +44,14 @@ static int _parse(rapidxml_DocumentObject* self, } try { self->base.base.document->clear(); - if (!parse_cdata){ - (self->base.base.document - ->parse) - (self->base.base.document->allocate_string(text)); - - }else{ - (self->base.base.document - ->parse) - (self->base.base.document->allocate_string(text)); - } - + char* data = self->base.base.document->allocate_string(text); + if (!parse_cdata) { + (self->base.base.document + ->parse)(data); + } else { + (self->base.base.document + ->parse)(data); + } } catch (rapidxml::parse_error &e) { PyErr_SetString(rapidxml_RapidXmlError, e.what()); return 0; @@ -78,7 +76,8 @@ static PyObject* rapidxml_DocumentObject_parse(rapidxml_DocumentObject* self, } if (!_parse(self, &text_buff, - (from_file_obj != NULL) && PyObject_IsTrue(from_file_obj), (read_cdata != NULL) && PyObject_IsTrue(read_cdata))) { + (from_file_obj != NULL) && PyObject_IsTrue(from_file_obj), + (read_cdata != NULL) && PyObject_IsTrue(read_cdata))) { return NULL; } Py_INCREF(Py_None); @@ -106,7 +105,10 @@ static int rapidxml_DocumentObject_init(rapidxml_DocumentObject* self, self->base.base.underlying_obj = new rapidxml::xml_document<>(); self->base.base.document = static_cast*>(self->base.base.underlying_obj); if (text_buff.buf) { - return _parse(self, &text_buff, (from_file_obj != NULL) && PyObject_IsTrue(from_file_obj), (read_cdata != NULL) && PyObject_IsTrue(read_cdata)) - 1; + return (_parse(self, &text_buff, + (from_file_obj != NULL) && PyObject_IsTrue(from_file_obj), + (read_cdata != NULL) && PyObject_IsTrue(read_cdata)) + - 1); } return 0; } diff --git a/rapidxml/rapidxml.py b/rapidxml/rapidxml.py index 7f8d1c9..86c467f 100644 --- a/rapidxml/rapidxml.py +++ b/rapidxml/rapidxml.py @@ -101,7 +101,7 @@ def __init__(self, attribute_prefix='@', cdata_key='#text', always_aslist=False, - parse_cdata=False): + parse_cdata=False): DictNode.__init__(self, attribute_prefix, cdata_key, always_aslist) rapidxml.c_ext.Document.__init__(self, text, from_file, parse_cdata) @@ -109,4 +109,3 @@ def allocate_node(self, *args): return DictNode(self.attribute_prefix, self.cdata_key, self.always_aslist).copy(super(RapidXml, self).allocate_node(*args)) - diff --git a/tests/conftest.py b/tests/conftest.py index ffaa97c..269ccd3 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -22,14 +22,24 @@ def init_rapidxml(): some text """) return r - + @pytest.fixture(scope="function") def init_rapidxml_with_CDADA(): - datra_str = "some text" - r = rapidxml.RapidXml(datra_str, - from_file=False, - attribute_prefix='@', - cdata_key='#text', - always_aslist=False, - parse_cdata=True) + data = b"some text" + r = rapidxml.RapidXml(data, parse_cdata=True) return r + +@pytest.fixture(scope="module") +def cdata_obj(): + return { + "Cart": { + "expirationTime": "2017-04-22T09:40", + "id": "b469df3b-f626-4fe3-898c-825373e546a2", + "products": ["1223"], + "creationTime":"2017-04-21T09:40", + "totalPrice": { + "currencyCode": "EUR", + "amount": "138.000", + }, + }, + } diff --git a/tests/test_cdata.py b/tests/test_cdata.py deleted file mode 100644 index 4aba0ea..0000000 --- a/tests/test_cdata.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env python -# -*- encoding: utf-8 -*- -# -# File: test_cdata.py -# by Amedeo Bussi -# amedeobussi@live.it -# - -import sys -import rapidxml -import ast - -def test_cdata(): - data = "" - - object = \ - { - "Cart": - { - "expirationTime":"2017-04-22T09:40", - "id":"b469df3b-f626-4fe3-898c-825373e546a2", - "products":["1223"], - "creationTime":"2017-04-21T09:40", - "totalPrice": - { - "currencyCode":"EUR", - "amount":"138.000" - } - } - } - - r = rapidxml.RapidXml(data, - from_file=False, - attribute_prefix='@', - cdata_key='#text', - always_aslist=False, - parse_cdata=True) - - object_received = ast.literal_eval(r.first_node().first_node().first_node().value) - - assert object_received == object - - - diff --git a/tests/test_nodes.py b/tests/test_nodes.py index 9099091..2f6e3ac 100644 --- a/tests/test_nodes.py +++ b/tests/test_nodes.py @@ -6,7 +6,7 @@ # arzaroth@arzaroth.com # -import ast +import json def test_first_node(init_rapidxml): root = init_rapidxml.first_node() @@ -38,26 +38,11 @@ def test_first_node_cdata(init_rapidxml_with_CDADA): assert root.first_node() == root.first_node("test") assert root.first_node() != root.first_node("test2") -def test_last_node_cdata(init_rapidxml_with_CDADA): +def test_last_node_cdata(init_rapidxml_with_CDADA, cdata_obj): root = init_rapidxml_with_CDADA.first_node() assert root.first_node() != root.last_node() assert root.first_node("test2") == root.last_node("test2") - object = \ - { - "Cart": - { - "expirationTime":"2017-04-22T09:40", - "id":"b469df3b-f626-4fe3-898c-825373e546a2", - "products":["1223"], - "creationTime":"2017-04-21T09:40", - "totalPrice": - { - "currencyCode":"EUR", - "amount":"138.000" - } - } - } - assert ast.literal_eval(root.last_node().first_node().first_node().value) == object + assert json.loads(root.last_node().first_node().first_node().value) == cdata_obj def test_nested_node_cdata(init_rapidxml_with_CDADA): test = init_rapidxml_with_CDADA.first_node().first_node("test") diff --git a/tests/test_utf8.py b/tests/test_utf8.py index 5512459..20fab6f 100644 --- a/tests/test_utf8.py +++ b/tests/test_utf8.py @@ -19,3 +19,14 @@ def test_utf8(): assert data == r.unparse(raw=True) r.first_node().value = b'\x85' assert r.unparse(raw=True).decode('cp1252').encode('utf-8') == b"\xe2\x80\xa6" + +def test_utf8_cdata(): + data = "" + if sys.version_info[0] >= 3: + data = data.encode('utf-8') + r = rapidxml.RapidXml(data, parse_cdata=True) + assert str(r) == r.unparse(pretty=True) + assert repr(r) == r.unparse() + assert data == r.unparse(raw=True) + r.first_node().first_node().value = b'\x85' + assert r.unparse(raw=True).decode('cp1252').encode('utf-8') == b"" From 45d7d2225e1e608b196043bac0cf4a2ef65886d9 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Wed, 24 May 2017 11:51:56 +0200 Subject: [PATCH 093/101] bump version & update readme --- README.md | 45 +++++++++++++++++++++++---------------------- setup.py | 2 +- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 293188a..202faad 100644 --- a/README.md +++ b/README.md @@ -4,38 +4,39 @@ A library providing python bindings for rapidxml ### Example - import rapidxml +```python +import rapidxml - r = rapidxml.RapidXml(b"foo") # parsing from bytes - test = r.first_node("test") # get first node named test - test.name = "foo" # changing node's name to foo - r.first_node("test2").value = "bar" # changing node's value to bar +r = rapidxml.RapidXml(b"foo") # parsing from bytes +test = r.first_node("test") # get first node named test +test.name = "foo" # changing node's name to foo +r.first_node("test2").value = "bar" # changing node's value to bar - print(str(r)) # will output a prettified string of the xml document - print(r.unparse(pretty=False, raw=True)) # will output the xml document as flat bytes - print(test) # also works for nodes +print(str(r)) # will output a prettified string of the xml document +print(r.unparse(pretty=False, raw=True)) # will output the xml document as flat bytes +print(test) # also works for nodes - with open('dump.xml', 'w') as f: - f.write(str(r)) - r = rapidxml.RapidXml("dump.xml", True) # loading from file - - assert(str(r) == r.unparse(True, False)) # is always True - assert(repr(r) == r.unparse(pretty=False, raw=False)) # also always True +with open('dump.xml', 'w') as f: + f.write(str(r)) +r = rapidxml.RapidXml("dump.xml", from_file=True) # loading from file +assert(str(r) == r.unparse(True, False)) # is always True +assert(repr(r) == r.unparse(pretty=False, raw=False)) # also always True +``` ### Install -[![Latest Version](https://pypip.in/version/RapidXml/badge.svg)](https://pypi.python.org/pypi/RapidXml/) -[![Supported Python Versions](https://pypip.in/py_versions/RapidXml/badge.svg)](https://pypi.python.org/pypi/RapidXml/) +[![Latest Version](https://img.shields.io/pypi/v/RapidXml.svg)](https://pypi.python.org/pypi/RapidXml/) +[![Supported Python Versions](https://img.shields.io/pypi/pyversions/RapidXml.svg)](https://pypi.python.org/pypi/RapidXml/) If you have downloaded the source code: - +```sh python setup.py install - +``` or if you want to obtain a copy from the Pypi repository: - +```sh pip install rapidxml - +``` Both commands will install the required package dependencies. A distribution package can be obtained for manual installation at: @@ -46,9 +47,9 @@ A distribution package can be obtained for manual installation at: ### Source python_rapidxml's git repo is available on GitHub, which can be browsed at [github](https://github.com/Arzaroth/python_rapidxml) and cloned like that: - +```sh git clone https://github.com/Arzaroth/python_rapidxml.git - +``` ### License diff --git a/setup.py b/setup.py index a44a555..7d5c0b6 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ from setuptools import setup, Extension, find_packages -VERSION = ("2", "0", "0") +VERSION = ("2", "1", "0") rapidxml = Extension("rapidxml.c_ext", define_macros=[('MAJOR_VERSION', VERSION[0]), From 292b9fba963795e5fd4141a0557082eba94f74d4 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Wed, 24 May 2017 11:54:12 +0200 Subject: [PATCH 094/101] use master travis badge --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 202faad..04ee05d 100644 --- a/README.md +++ b/README.md @@ -31,11 +31,11 @@ assert(repr(r) == r.unparse(pretty=False, raw=False)) # also always True If you have downloaded the source code: ```sh - python setup.py install +python setup.py install ``` or if you want to obtain a copy from the Pypi repository: ```sh - pip install rapidxml +pip install rapidxml ``` Both commands will install the required package dependencies. @@ -48,7 +48,7 @@ A distribution package can be obtained for manual installation at: python_rapidxml's git repo is available on GitHub, which can be browsed at [github](https://github.com/Arzaroth/python_rapidxml) and cloned like that: ```sh - git clone https://github.com/Arzaroth/python_rapidxml.git +git clone https://github.com/Arzaroth/python_rapidxml.git ``` ### License @@ -58,6 +58,6 @@ MIT license. See the LICENSE file. ### Development status -[![Build Status](https://travis-ci.org/Arzaroth/python_rapidxml.svg?branch=2.0)](https://travis-ci.org/Arzaroth/python_rapidxml) +[![Build Status](https://travis-ci.org/Arzaroth/python_rapidxml.svg?branch=master)](https://travis-ci.org/Arzaroth/python_rapidxml) This project is currently under development. From 3af43b66b5073f8cc1bf22472d64a1ab246cd1bc Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Wed, 24 May 2017 15:53:59 +0200 Subject: [PATCH 095/101] fix argparsing & py3.5/py3.6 compat --- README.md | 2 +- rapidxml/__init__.py | 2 +- rapidxml/c_ext/src/base_object.cpp | 3 +- rapidxml/c_ext/src/common.cpp | 3 +- rapidxml/c_ext/src/document_object.cpp | 18 ++---- rapidxml/c_ext/src/node_object.cpp | 86 ++++++++++++-------------- setup.py | 5 +- test-requirements.txt | 4 +- tests/test_basic.py | 11 +++- 9 files changed, 61 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index 04ee05d..2a35081 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ with open('dump.xml', 'w') as f: f.write(str(r)) r = rapidxml.RapidXml("dump.xml", from_file=True) # loading from file -assert(str(r) == r.unparse(True, False)) # is always True +assert(str(r) == r.unparse(pretty=True, raw=False)) # is always True assert(repr(r) == r.unparse(pretty=False, raw=False)) # also always True ``` diff --git a/rapidxml/__init__.py b/rapidxml/__init__.py index 5a8ca54..cd26c39 100644 --- a/rapidxml/__init__.py +++ b/rapidxml/__init__.py @@ -11,4 +11,4 @@ __all__ = [ 'RapidXml', 'DictNode', - ] +] diff --git a/rapidxml/c_ext/src/base_object.cpp b/rapidxml/c_ext/src/base_object.cpp index 3792614..2a30b00 100644 --- a/rapidxml/c_ext/src/base_object.cpp +++ b/rapidxml/c_ext/src/base_object.cpp @@ -40,9 +40,8 @@ static PyObject* rapidxml_BaseObject_copy(rapidxml_BaseObject* self, PyObject* args, PyObject* kwds) { PyObject* other = NULL; - char kw_other[] = "other"; - static char* kwlist[] = {kw_other, NULL}; + static char* kwlist[] = {"other", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &other)) { return NULL; diff --git a/rapidxml/c_ext/src/common.cpp b/rapidxml/c_ext/src/common.cpp index fc74fc5..7a66986 100644 --- a/rapidxml/c_ext/src/common.cpp +++ b/rapidxml/c_ext/src/common.cpp @@ -16,10 +16,9 @@ int _parse_args_for_name(PyObject* args, PyObject* kwds, const char** name) { - char kw_name[] = "name"; Py_buffer buf = {0}; - static char* kwlist[] = {kw_name, NULL}; + static char* kwlist[] = {"name", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s*", kwlist, &buf)) { return false; diff --git a/rapidxml/c_ext/src/document_object.cpp b/rapidxml/c_ext/src/document_object.cpp index 685ded0..d4c5cb5 100644 --- a/rapidxml/c_ext/src/document_object.cpp +++ b/rapidxml/c_ext/src/document_object.cpp @@ -65,11 +65,8 @@ static PyObject* rapidxml_DocumentObject_parse(rapidxml_DocumentObject* self, Py_buffer text_buff; PyObject* from_file_obj = NULL; PyObject* read_cdata = NULL; - char kw_text[] = "text"; - char kw_from_file[] = "from_file"; - char kw_parse_cdata[] = "parse_cdata"; - static char* kwlist[] = {kw_text, kw_from_file, kw_parse_cdata, NULL}; + static char* kwlist[] = {"text", "from_file", "parse_cdata", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "s*|OO", kwlist, &text_buff, &from_file_obj, &read_cdata)) { return NULL; @@ -90,14 +87,11 @@ static int rapidxml_DocumentObject_init(rapidxml_DocumentObject* self, Py_buffer text_buff = {0}; PyObject* from_file_obj = NULL; PyObject* read_cdata = NULL; - char kw_text[] = "text"; - char kw_from_file[] = "from_file"; - char kw_parse_cdata[] = "parse_cdata"; if (rapidxml_NodeType.tp_init(reinterpret_cast(self), args, kwds) < 0) { return -1; } - static char* kwlist[] = {kw_text, kw_from_file, kw_parse_cdata, NULL}; + static char* kwlist[] = {"text", "from_file", "parse_cdata", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s*OO", kwlist, &text_buff, &from_file_obj, &read_cdata)) { return -1; @@ -120,11 +114,9 @@ static PyObject* rapidxml_DocumentObject_allocate_node(rapidxml_DocumentObject* Py_buffer name_buff = {0}; const char* value; Py_buffer value_buff = {0}; - char kw_name[] = "name"; - char kw_value[] = "value"; rapidxml::xml_node<>* node; - static char* kwlist[] = {kw_name, kw_value, NULL}; + static char* kwlist[] = {"name", "value", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s*s*", kwlist, &name_buff, &value_buff)) { Py_INCREF(Py_None); @@ -150,11 +142,9 @@ static PyObject* rapidxml_DocumentObject_allocate_attribute(rapidxml_DocumentObj Py_buffer name_buff = {0}; const char* value; Py_buffer value_buff = {0}; - char kw_name[] = "name"; - char kw_value[] = "value"; rapidxml::xml_attribute<>* attribute; - static char* kwlist[] = {kw_name, kw_value, NULL}; + static char* kwlist[] = {"name", "value", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s*s*", kwlist, &name_buff, &value_buff)) { Py_INCREF(Py_None); diff --git a/rapidxml/c_ext/src/node_object.cpp b/rapidxml/c_ext/src/node_object.cpp index ea147db..97687be 100644 --- a/rapidxml/c_ext/src/node_object.cpp +++ b/rapidxml/c_ext/src/node_object.cpp @@ -164,10 +164,9 @@ static PyObject* rapidxml_NodeObject_last_attribute(rapidxml_NodeObject* self, static PyObject* rapidxml_NodeObject_prepend_node(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { - char kw_node[] = "node"; PyObject* node = NULL; - static char* kwlist[] = {kw_node, NULL}; + static char* kwlist[] = {"node", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &node)) { return NULL; @@ -186,10 +185,9 @@ static PyObject* rapidxml_NodeObject_prepend_node(rapidxml_NodeObject* self, static PyObject* rapidxml_NodeObject_append_node(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { - char kw_node[] = "node"; PyObject* node = NULL; - static char* kwlist[] = {kw_node, NULL}; + static char* kwlist[] = {"node", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &node)) { return NULL; @@ -208,12 +206,10 @@ static PyObject* rapidxml_NodeObject_append_node(rapidxml_NodeObject* self, static PyObject* rapidxml_NodeObject_insert_node(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { - char kw_where[] = "where"; - char kw_node[] = "node"; PyObject* where = NULL; PyObject* node = NULL; - static char* kwlist[] = {kw_where, kw_node, NULL}; + static char* kwlist[] = {"where", "node", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &where, &node)) { return NULL; @@ -254,10 +250,9 @@ static PyObject* rapidxml_NodeObject_remove_last_node(rapidxml_NodeObject* self, static PyObject* rapidxml_NodeObject_remove_node(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { - char kw_node[] = "node"; PyObject* node = NULL; - static char* kwlist[] = {kw_node, NULL}; + static char* kwlist[] = {"node", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &node)) { return NULL; @@ -284,10 +279,9 @@ static PyObject* rapidxml_NodeObject_remove_all_nodes(rapidxml_NodeObject* self, static PyObject* rapidxml_NodeObject_prepend_attribute(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { - char kw_attribute[] = "attribute"; PyObject* attribute = NULL; - static char* kwlist[] = {kw_attribute, NULL}; + static char* kwlist[] = {"attribute", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &attribute)) { return NULL; @@ -306,10 +300,9 @@ static PyObject* rapidxml_NodeObject_prepend_attribute(rapidxml_NodeObject* self static PyObject* rapidxml_NodeObject_append_attribute(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { - char kw_attribute[] = "attribute"; PyObject* attribute = NULL; - static char* kwlist[] = {kw_attribute, NULL}; + static char* kwlist[] = {"attribute", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &attribute)) { return NULL; @@ -328,12 +321,10 @@ static PyObject* rapidxml_NodeObject_append_attribute(rapidxml_NodeObject* self, static PyObject* rapidxml_NodeObject_insert_attribute(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { - char kw_where[] = "where"; - char kw_attribute[] = "attribute"; PyObject* where = NULL; PyObject* attribute = NULL; - static char* kwlist[] = {kw_where, kw_attribute, NULL}; + static char* kwlist[] = {"where", "attribute", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &where, &attribute)) { return NULL; @@ -374,10 +365,9 @@ static PyObject* rapidxml_NodeObject_remove_last_attribute(rapidxml_NodeObject* static PyObject* rapidxml_NodeObject_remove_attribute(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { - char kw_attribute[] = "attribute"; PyObject* attribute = NULL; - static char* kwlist[] = {kw_attribute, NULL}; + static char* kwlist[] = {"attribute", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &attribute)) { return NULL; @@ -401,27 +391,16 @@ static PyObject* rapidxml_NodeObject_remove_all_attributes(rapidxml_NodeObject* return Py_None; } -static PyObject* rapidxml_NodeObject_unparse(rapidxml_NodeObject* self, - PyObject* args, - PyObject* kwds) { - PyObject* pretty_obj = NULL; - PyObject* raw_obj = NULL; - PyObject* res; +static PyObject* _unparse(rapidxml_NodeObject* self, + bool pretty, + bool raw) { + PyObject* res = NULL; std::string xml; - char kw_pretty[] = "pretty"; - char kw_raw[] = "raw"; - - static char* kwlist[] = {kw_pretty, kw_raw, NULL}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist, - &pretty_obj, &raw_obj)) { - return NULL; - } rapidxml::print(std::back_inserter(xml), *(static_cast*>(self->base.underlying_obj)), - ((pretty_obj == NULL) || PyObject_Not(pretty_obj)) - ? rapidxml::print_no_indenting : 0); - if ((raw_obj == NULL) || PyObject_Not(raw_obj) + !pretty ? rapidxml::print_no_indenting : 0); + if (!raw #if PY_MAJOR_VERSION < 3 || true #endif @@ -433,24 +412,35 @@ static PyObject* rapidxml_NodeObject_unparse(rapidxml_NodeObject* self, return res; } -static PyObject* rapidxml_NodeObject___str__(rapidxml_NodeObject* self) { - PyObject* args; - PyObject* res; +static PyObject* rapidxml_NodeObject_unparse(rapidxml_NodeObject* self, + PyObject* args, + PyObject* kwds) { + PyObject* pretty_obj = NULL; + PyObject* raw_obj = NULL; + PyObject* res = NULL; + std::string xml; - args = Py_BuildValue("(O)", Py_True); - res = rapidxml_NodeObject_unparse(self, args, NULL); - Py_DECREF(args); + static char* kwlist[] = {"pretty", "raw", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO:unparse", kwlist, + &pretty_obj, &raw_obj)) { + return NULL; + } + Py_XINCREF(pretty_obj); + Py_XINCREF(raw_obj); + res = _unparse(self, + (pretty_obj != NULL && PyObject_IsTrue(pretty_obj)), + (raw_obj != NULL && PyObject_IsTrue(raw_obj))); + Py_XDECREF(pretty_obj); + Py_XDECREF(raw_obj); return res; } -static PyObject* rapidxml_NodeObject___repr__(rapidxml_NodeObject* self) { - PyObject* args; - PyObject* res; +static PyObject* rapidxml_NodeObject___str__(rapidxml_NodeObject* self) { + return _unparse(self, true, false); +} - args = Py_BuildValue("()"); - res = rapidxml_NodeObject_unparse(self, args, NULL); - Py_DECREF(args); - return res; +static PyObject* rapidxml_NodeObject___repr__(rapidxml_NodeObject* self) { + return _unparse(self, false, false); } static PyObject* rapidxml_NodeObject_children(rapidxml_NodeObject* self, diff --git a/setup.py b/setup.py index 7d5c0b6..64299cd 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,8 @@ # arzaroth@arzaroth.com # -from setuptools import setup, Extension, find_packages +from setuptools import setup, find_packages +from setuptools import Extension VERSION = ("2", "1", "0") @@ -63,5 +64,7 @@ "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", ], ) diff --git a/test-requirements.txt b/test-requirements.txt index e004cf0..d732b0e 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,2 +1,2 @@ -py==1.4.26 -pytest==2.7.0 +py==1.4.33 +pytest==3.1.0 diff --git a/tests/test_basic.py b/tests/test_basic.py index 3883915..14fa901 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -9,12 +9,20 @@ import os import rapidxml -def test_init(init_rapidxml): +def test_unparse(init_rapidxml): assert init_rapidxml.unparse() == ('' '' 'some text') assert init_rapidxml.unparse() == repr(init_rapidxml) + assert init_rapidxml.unparse(False, False) == repr(init_rapidxml) + assert init_rapidxml.unparse(raw=False) == repr(init_rapidxml) + assert init_rapidxml.unparse(pretty=False) == repr(init_rapidxml) + assert init_rapidxml.unparse(pretty=False, raw=False) == repr(init_rapidxml) assert init_rapidxml.unparse(True) == str(init_rapidxml) + assert init_rapidxml.unparse(True, False) == str(init_rapidxml) + assert init_rapidxml.unparse(pretty=True) == str(init_rapidxml) + assert init_rapidxml.unparse(pretty=True, raw=False) == str(init_rapidxml) + assert init_rapidxml.unparse(True, raw=False) == str(init_rapidxml) def test_parse(init_rapidxml): r = rapidxml.RapidXml() @@ -115,4 +123,3 @@ def test_assign_cdata(init_rapidxml_with_CDADA): test = root.first_node("test") test.value = "some new text" assert test.value == "some new text" - From 4b38c8441dfe5ca7caaa01259a156400e7c0bef6 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Wed, 24 May 2017 15:58:14 +0200 Subject: [PATCH 096/101] rename readme --- README.md => README | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename README.md => README (100%) diff --git a/README.md b/README similarity index 100% rename from README.md rename to README From 1469ba3173f8643a2bf69764dc011d3caddf45f1 Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Wed, 24 May 2017 16:00:32 +0200 Subject: [PATCH 097/101] nothing to see here --- README => README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename README => README.md (100%) diff --git a/README b/README.md similarity index 100% rename from README rename to README.md From 3d1b509195181e643d947531a4a2141c947d9f0c Mon Sep 17 00:00:00 2001 From: Arzaroth Lekva Date: Wed, 24 May 2017 16:09:41 +0200 Subject: [PATCH 098/101] bump minor version --- setup.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 64299cd..5a6e5d7 100644 --- a/setup.py +++ b/setup.py @@ -6,10 +6,23 @@ # arzaroth@arzaroth.com # +import os +import io + from setuptools import setup, find_packages from setuptools import Extension -VERSION = ("2", "1", "0") +long_descr = 'Python bindings for RapidXml, a C++ XML parsing library' +try: + import pypandoc + long_descr = pypandoc.convert('README.md', 'rst') + long_descr = long_descr.replace("\r", "") +except (ImportError, OSError): + if os.path.exists('README.md'): + with io.open('README.md', encoding="utf-8") as f: + long_descr = f.read() + +VERSION = ("2", "1", "1") rapidxml = Extension("rapidxml.c_ext", define_macros=[('MAJOR_VERSION', VERSION[0]), @@ -43,7 +56,7 @@ author_email='lekva@arzaroth.com', description='Python RapidXml Library', - long_description='python bindings for RapidXml, a C++ XML parsing library', + long_description=long_descr, keywords='rapidxml xml parsing', packages=find_packages('.'), From d757e77bd7e92f0d82840725c72d2f67e1c8dc0d Mon Sep 17 00:00:00 2001 From: Marc-Etienne Barrut Date: Thu, 6 Nov 2025 00:06:12 +0100 Subject: [PATCH 099/101] fix Python buffers & C++ doc leaks, add modern Python support (fixes #7) (#9) --- README.md | 5 --- rapidxml/c_ext/inc/common.h | 2 +- rapidxml/c_ext/src/attribute_object.cpp | 18 ++++++++- rapidxml/c_ext/src/base_object.cpp | 6 ++- rapidxml/c_ext/src/common.cpp | 13 ++++-- rapidxml/c_ext/src/document_object.cpp | 41 +++++++++++++------ rapidxml/c_ext/src/node_object.cpp | 54 ++++++++++++++++++++++--- rapidxml/rapidxml.py | 2 +- setup.py | 9 ++++- test-requirements.txt | 3 +- 10 files changed, 117 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 2a35081..eb8ba95 100644 --- a/README.md +++ b/README.md @@ -56,8 +56,3 @@ git clone https://github.com/Arzaroth/python_rapidxml.git MIT license. See the LICENSE file. -### Development status - -[![Build Status](https://travis-ci.org/Arzaroth/python_rapidxml.svg?branch=master)](https://travis-ci.org/Arzaroth/python_rapidxml) - -This project is currently under development. diff --git a/rapidxml/c_ext/inc/common.h b/rapidxml/c_ext/inc/common.h index a0eb39e..8c6de3a 100644 --- a/rapidxml/c_ext/inc/common.h +++ b/rapidxml/c_ext/inc/common.h @@ -76,7 +76,7 @@ extern PyObject* rapidxml_RapidXmlError; ** Utility functions */ -int _parse_args_for_name(PyObject*, PyObject*, const char**); +int _parse_args_for_name(PyObject*, PyObject*, Py_buffer*, const char**); PyObject* _bind_result(rapidxml_BaseObject*, rapidxml::xml_base<>*, PyTypeObject*); /* diff --git a/rapidxml/c_ext/src/attribute_object.cpp b/rapidxml/c_ext/src/attribute_object.cpp index 95ff875..0fb70f4 100644 --- a/rapidxml/c_ext/src/attribute_object.cpp +++ b/rapidxml/c_ext/src/attribute_object.cpp @@ -24,18 +24,25 @@ static PyObject* rapidxml_AttributeObject_previous_attribute(rapidxml_AttributeO PyObject* args, PyObject* kwds) { const char* name = NULL; + Py_buffer name_buff = {0}; rapidxml::xml_attribute<>* attribute; - if (!_parse_args_for_name(args, kwds, &name)) { + if (!_parse_args_for_name(args, kwds, &name_buff, &name)) { goto err; } attribute = static_cast*>(self->base.underlying_obj)->previous_attribute(name); if (attribute == NULL) { goto err; } + if (name_buff.buf) { + PyBuffer_Release(&name_buff); + } return _bind_result(reinterpret_cast(self), attribute, &rapidxml_AttributeType); err: + if (name_buff.buf) { + PyBuffer_Release(&name_buff); + } Py_INCREF(Py_None); return Py_None; } @@ -44,18 +51,25 @@ static PyObject* rapidxml_AttributeObject_next_attribute(rapidxml_AttributeObjec PyObject* args, PyObject* kwds) { const char* name = NULL; + Py_buffer name_buff = {0}; rapidxml::xml_attribute<>* attribute; - if (!_parse_args_for_name(args, kwds, &name)) { + if (!_parse_args_for_name(args, kwds, &name_buff, &name)) { goto err; } attribute = static_cast*>(self->base.underlying_obj)->next_attribute(name); if (attribute == NULL) { goto err; } + if (name_buff.buf) { + PyBuffer_Release(&name_buff); + } return _bind_result(reinterpret_cast(self), attribute, &rapidxml_AttributeType); err: + if (name_buff.buf) { + PyBuffer_Release(&name_buff); + } Py_INCREF(Py_None); return Py_None; } diff --git a/rapidxml/c_ext/src/base_object.cpp b/rapidxml/c_ext/src/base_object.cpp index 2a30b00..8d7364b 100644 --- a/rapidxml/c_ext/src/base_object.cpp +++ b/rapidxml/c_ext/src/base_object.cpp @@ -106,7 +106,7 @@ static PyObject* rapidxml_BaseObject_getname(rapidxml_BaseObject* self, static int rapidxml_BaseObject_setname(rapidxml_BaseObject* self, PyObject* arg, void* closure) { - Py_buffer name; + Py_buffer name = {0}; if (self->underlying_obj == NULL || self->document == NULL) { PyErr_SetString(rapidxml_RapidXmlError, @@ -122,6 +122,7 @@ static int rapidxml_BaseObject_setname(rapidxml_BaseObject* self, return -1; } self->underlying_obj->name(self->document->allocate_string(static_cast(name.buf))); + PyBuffer_Release(&name); return 0; } @@ -147,7 +148,7 @@ static PyObject* rapidxml_BaseObject_getvalue(rapidxml_BaseObject* self, static int rapidxml_BaseObject_setvalue(rapidxml_BaseObject* self, PyObject* arg, void* closure) { - Py_buffer value; + Py_buffer value = {0}; if (self->underlying_obj == NULL || self->document == NULL) { PyErr_SetString(rapidxml_RapidXmlError, @@ -163,6 +164,7 @@ static int rapidxml_BaseObject_setvalue(rapidxml_BaseObject* self, return -1; } self->underlying_obj->value(self->document->allocate_string(static_cast(value.buf))); + PyBuffer_Release(&value); return 0; } diff --git a/rapidxml/c_ext/src/common.cpp b/rapidxml/c_ext/src/common.cpp index 7a66986..4eb3ba3 100644 --- a/rapidxml/c_ext/src/common.cpp +++ b/rapidxml/c_ext/src/common.cpp @@ -15,16 +15,21 @@ int _parse_args_for_name(PyObject* args, PyObject* kwds, + Py_buffer* buf, const char** name) { - Py_buffer buf = {0}; + *name = NULL; + if (buf != NULL) { + buf->buf = NULL; + buf->obj = NULL; + } static char* kwlist[] = {"name", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s*", kwlist, - &buf)) { + buf)) { return false; } - if (buf.buf) { - *name = static_cast(buf.buf); + if (buf != NULL && buf->buf) { + *name = static_cast(buf->buf); } return true; } diff --git a/rapidxml/c_ext/src/document_object.cpp b/rapidxml/c_ext/src/document_object.cpp index d4c5cb5..aaaf0bd 100644 --- a/rapidxml/c_ext/src/document_object.cpp +++ b/rapidxml/c_ext/src/document_object.cpp @@ -62,7 +62,7 @@ static int _parse(rapidxml_DocumentObject* self, static PyObject* rapidxml_DocumentObject_parse(rapidxml_DocumentObject* self, PyObject* args, PyObject* kwds) { - Py_buffer text_buff; + Py_buffer text_buff = {0}; PyObject* from_file_obj = NULL; PyObject* read_cdata = NULL; @@ -72,9 +72,13 @@ static PyObject* rapidxml_DocumentObject_parse(rapidxml_DocumentObject* self, return NULL; } - if (!_parse(self, &text_buff, - (from_file_obj != NULL) && PyObject_IsTrue(from_file_obj), - (read_cdata != NULL) && PyObject_IsTrue(read_cdata))) { + int parsed = _parse(self, &text_buff, + (from_file_obj != NULL) && PyObject_IsTrue(from_file_obj), + (read_cdata != NULL) && PyObject_IsTrue(read_cdata)); + if (text_buff.buf) { + PyBuffer_Release(&text_buff); + } + if (!parsed) { return NULL; } Py_INCREF(Py_None); @@ -99,10 +103,11 @@ static int rapidxml_DocumentObject_init(rapidxml_DocumentObject* self, self->base.base.underlying_obj = new rapidxml::xml_document<>(); self->base.base.document = static_cast*>(self->base.base.underlying_obj); if (text_buff.buf) { - return (_parse(self, &text_buff, - (from_file_obj != NULL) && PyObject_IsTrue(from_file_obj), - (read_cdata != NULL) && PyObject_IsTrue(read_cdata)) - - 1); + int parsed = _parse(self, &text_buff, + (from_file_obj != NULL) && PyObject_IsTrue(from_file_obj), + (read_cdata != NULL) && PyObject_IsTrue(read_cdata)); + PyBuffer_Release(&text_buff); + return parsed - 1; } return 0; } @@ -110,9 +115,9 @@ static int rapidxml_DocumentObject_init(rapidxml_DocumentObject* self, static PyObject* rapidxml_DocumentObject_allocate_node(rapidxml_DocumentObject* self, PyObject* args, PyObject* kwds) { - const char* name; + const char* name = NULL; Py_buffer name_buff = {0}; - const char* value; + const char* value = NULL; Py_buffer value_buff = {0}; rapidxml::xml_node<>* node; @@ -131,6 +136,12 @@ static PyObject* rapidxml_DocumentObject_allocate_node(rapidxml_DocumentObject* value = self->base.base.document->allocate_string(value); } node = self->base.base.document->allocate_node(rapidxml::node_element, name, value); + if (name_buff.buf) { + PyBuffer_Release(&name_buff); + } + if (value_buff.buf) { + PyBuffer_Release(&value_buff); + } return _bind_result(reinterpret_cast(self), node, &rapidxml_NodeType); } @@ -138,9 +149,9 @@ static PyObject* rapidxml_DocumentObject_allocate_node(rapidxml_DocumentObject* static PyObject* rapidxml_DocumentObject_allocate_attribute(rapidxml_DocumentObject* self, PyObject* args, PyObject* kwds) { - const char* name; + const char* name = NULL; Py_buffer name_buff = {0}; - const char* value; + const char* value = NULL; Py_buffer value_buff = {0}; rapidxml::xml_attribute<>* attribute; @@ -159,6 +170,12 @@ static PyObject* rapidxml_DocumentObject_allocate_attribute(rapidxml_DocumentObj value = self->base.base.document->allocate_string(value); } attribute = self->base.base.document->allocate_attribute(name, value); + if (name_buff.buf) { + PyBuffer_Release(&name_buff); + } + if (value_buff.buf) { + PyBuffer_Release(&value_buff); + } return _bind_result(reinterpret_cast(self), attribute, &rapidxml_AttributeType); } diff --git a/rapidxml/c_ext/src/node_object.cpp b/rapidxml/c_ext/src/node_object.cpp index 97687be..931928d 100644 --- a/rapidxml/c_ext/src/node_object.cpp +++ b/rapidxml/c_ext/src/node_object.cpp @@ -42,18 +42,25 @@ static PyObject* rapidxml_NodeObject_first_node(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { const char* name = NULL; + Py_buffer name_buff = {0}; rapidxml::xml_node<>* node; - if (!_parse_args_for_name(args, kwds, &name)) { + if (!_parse_args_for_name(args, kwds, &name_buff, &name)) { goto err; } node = static_cast*>(self->base.underlying_obj)->first_node(name); if (node == NULL) { goto err; } + if (name_buff.buf) { + PyBuffer_Release(&name_buff); + } return _bind_result(reinterpret_cast(self), node, &rapidxml_NodeType); err: + if (name_buff.buf) { + PyBuffer_Release(&name_buff); + } Py_INCREF(Py_None); return Py_None; } @@ -62,9 +69,10 @@ static PyObject* rapidxml_NodeObject_last_node(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { const char* name = NULL; + Py_buffer name_buff = {0}; rapidxml::xml_node<>* node; - if (!(_parse_args_for_name(args, kwds, &name) && + if (!(_parse_args_for_name(args, kwds, &name_buff, &name) && static_cast*>(self->base.underlying_obj)->first_node())) { goto err; } @@ -72,9 +80,15 @@ static PyObject* rapidxml_NodeObject_last_node(rapidxml_NodeObject* self, if (node == NULL) { goto err; } + if (name_buff.buf) { + PyBuffer_Release(&name_buff); + } return _bind_result(reinterpret_cast(self), node, &rapidxml_NodeType); err: + if (name_buff.buf) { + PyBuffer_Release(&name_buff); + } Py_INCREF(Py_None); return Py_None; } @@ -83,9 +97,10 @@ static PyObject* rapidxml_NodeObject_previous_sibling(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { const char* name = NULL; + Py_buffer name_buff = {0}; rapidxml::xml_node<>* node; - if (!(_parse_args_for_name(args, kwds, &name) && + if (!(_parse_args_for_name(args, kwds, &name_buff, &name) && static_cast*>(self->base.underlying_obj)->parent())) { goto err; } @@ -93,9 +108,15 @@ static PyObject* rapidxml_NodeObject_previous_sibling(rapidxml_NodeObject* self, if (node == NULL) { goto err; } + if (name_buff.buf) { + PyBuffer_Release(&name_buff); + } return _bind_result(reinterpret_cast(self), node, &rapidxml_NodeType); err: + if (name_buff.buf) { + PyBuffer_Release(&name_buff); + } Py_INCREF(Py_None); return Py_None; } @@ -104,9 +125,10 @@ static PyObject* rapidxml_NodeObject_next_sibling(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { const char* name = NULL; + Py_buffer name_buff = {0}; rapidxml::xml_node<>* node; - if (!(_parse_args_for_name(args, kwds, &name) && + if (!(_parse_args_for_name(args, kwds, &name_buff, &name) && static_cast*>(self->base.underlying_obj)->parent())) { goto err; } @@ -114,9 +136,15 @@ static PyObject* rapidxml_NodeObject_next_sibling(rapidxml_NodeObject* self, if (node == NULL) { goto err; } + if (name_buff.buf) { + PyBuffer_Release(&name_buff); + } return _bind_result(reinterpret_cast(self), node, &rapidxml_NodeType); err: + if (name_buff.buf) { + PyBuffer_Release(&name_buff); + } Py_INCREF(Py_None); return Py_None; } @@ -125,18 +153,25 @@ static PyObject* rapidxml_NodeObject_first_attribute(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { const char* name = NULL; + Py_buffer name_buff = {0}; rapidxml::xml_attribute<>* attribute; - if (!_parse_args_for_name(args, kwds, &name)) { + if (!_parse_args_for_name(args, kwds, &name_buff, &name)) { goto err; } attribute = static_cast*>(self->base.underlying_obj)->first_attribute(name); if (attribute == NULL) { goto err; } + if (name_buff.buf) { + PyBuffer_Release(&name_buff); + } return _bind_result(reinterpret_cast(self), attribute, &rapidxml_AttributeType); err: + if (name_buff.buf) { + PyBuffer_Release(&name_buff); + } Py_INCREF(Py_None); return Py_None; } @@ -145,18 +180,25 @@ static PyObject* rapidxml_NodeObject_last_attribute(rapidxml_NodeObject* self, PyObject* args, PyObject* kwds) { const char* name = NULL; + Py_buffer name_buff = {0}; rapidxml::xml_attribute<>* attribute; - if (!_parse_args_for_name(args, kwds, &name)) { + if (!_parse_args_for_name(args, kwds, &name_buff, &name)) { goto err; } attribute = static_cast*>(self->base.underlying_obj)->last_attribute(name); if (attribute == NULL) { goto err; } + if (name_buff.buf) { + PyBuffer_Release(&name_buff); + } return _bind_result(reinterpret_cast(self), attribute, &rapidxml_AttributeType); err: + if (name_buff.buf) { + PyBuffer_Release(&name_buff); + } Py_INCREF(Py_None); return Py_None; } diff --git a/rapidxml/rapidxml.py b/rapidxml/rapidxml.py index 86c467f..203c691 100644 --- a/rapidxml/rapidxml.py +++ b/rapidxml/rapidxml.py @@ -94,7 +94,7 @@ def __iter__(self): self.cdata_key, self.always_aslist) -class RapidXml(DictNode, rapidxml.c_ext.Document): +class RapidXml(rapidxml.c_ext.Document, DictNode): def __init__(self, text="", from_file=False, diff --git a/setup.py b/setup.py index 5a6e5d7..5261c15 100644 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ with io.open('README.md', encoding="utf-8") as f: long_descr = f.read() -VERSION = ("2", "1", "1") +VERSION = ("2", "1", "2") rapidxml = Extension("rapidxml.c_ext", define_macros=[('MAJOR_VERSION', VERSION[0]), @@ -79,5 +79,12 @@ "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", ], ) diff --git a/test-requirements.txt b/test-requirements.txt index d732b0e..9270945 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,2 +1 @@ -py==1.4.33 -pytest==3.1.0 +pytest==6.2.5 From 9c300eeba8fe2241caf951b844dd1dfbb5fb214e Mon Sep 17 00:00:00 2001 From: Marc-Etienne Barrut Date: Thu, 6 Nov 2025 00:36:46 +0100 Subject: [PATCH 100/101] remove readme markdown to rst conversion --- setup.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/setup.py b/setup.py index 5261c15..77d0a56 100644 --- a/setup.py +++ b/setup.py @@ -6,24 +6,23 @@ # arzaroth@arzaroth.com # -import os import io +import os -from setuptools import setup, find_packages -from setuptools import Extension +from setuptools import Extension, find_packages, setup -long_descr = 'Python bindings for RapidXml, a C++ XML parsing library' -try: - import pypandoc - long_descr = pypandoc.convert('README.md', 'rst') - long_descr = long_descr.replace("\r", "") -except (ImportError, OSError): - if os.path.exists('README.md'): - with io.open('README.md', encoding="utf-8") as f: - long_descr = f.read() + +def read_readme(): + readme_path = 'README.md' + if os.path.exists(readme_path): + with io.open(readme_path, encoding="utf-8") as fh: + return fh.read() + return 'Python bindings for RapidXml, a C++ XML parsing library' VERSION = ("2", "1", "2") +long_descr = read_readme() + rapidxml = Extension("rapidxml.c_ext", define_macros=[('MAJOR_VERSION', VERSION[0]), ('MINOR_VERSION', VERSION[1])], @@ -57,6 +56,7 @@ description='Python RapidXml Library', long_description=long_descr, + long_description_content_type='text/markdown', keywords='rapidxml xml parsing', packages=find_packages('.'), From 202836b88b557624b31752c163f6c9c4752cae44 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 18:36:04 +0000 Subject: [PATCH 101/101] Bump pytest from 6.2.5 to 9.0.3 Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.2.5 to 9.0.3. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/6.2.5...9.0.3) --- updated-dependencies: - dependency-name: pytest dependency-version: 9.0.3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- test-requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-requirements.txt b/test-requirements.txt index 9270945..b3b2b3c 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1 +1 @@ -pytest==6.2.5 +pytest==9.0.3