[libxml++] Improved handling of entity references and processing instructions.
- From: Kjell Ahlstedt <kjellahl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libxml++] Improved handling of entity references and processing instructions.
- Date: Wed, 15 Feb 2012 14:43:43 +0000 (UTC)
commit 09a10ea98255449c71ad07e389057cdbb80d2bb7
Author: Kjell Ahlstedt <kjell ahlstedt bredband net>
Date: Wed Feb 15 15:09:59 2012 +0100
Improved handling of entity references and processing instructions.
* libxml++/nodes/entitydeclaration.[h|cc]: New files.
* Makefile.am:
* libxml++/Makefile.am: Add the new files.
* libxml++/libxml++.h: Add the new .h file.
* docs/manual/libxml++_without_code.xml: Add EntityDeclaration in the list
of node classes.
* libxml++/document.[h|cc]: Add add_processing_instruction().
* libxml++/nodes/element.[h|cc]: Add add_child_entity_reference() and
add_child_processing_instruction().
* libxml++/nodes/entityreference.h: Improve the description of
get_resolved_text() and get_original_text().
* libxml++/nodes/node.cc: get_namespace_prefix() and get_namespace_uri():
XML_ENTITY_DECL has no namespace. Don't try to find it.
create_wrapper(): Create an EntityDeclaration when type == XML_ENTITY_DECL.
free_wrappers(): Don't walk the child list when type == XML_ENTITY_REF_NODE.
* examples/dom_build/main.cc: Add entity declarations and references, and
processing instructions to the built xml file.
* examples/dom_parse_entities/example.dtd: Make it compatible with example.xml.
* examples/dom_parse_entities/example.xml: Add an entity definition that
contains entity references.
* examples/dom_parse_entities/main.cc: Print the parsed file both with and
without entity substitution.
* examples/dom_parser/example.dtd: Make it compatible with example.xml.
* examples/dom_parser/main.cc: Add command flag -E (Don't substitute entities).
Bug #669481
ChangeLog | 30 +++++++++++
Makefile.am | 2 +
docs/manual/libxml++_without_code.xml | 3 +-
examples/dom_build/main.cc | 16 ++++--
examples/dom_parse_entities/example.dtd | 2 +-
examples/dom_parse_entities/example.xml | 7 +++
examples/dom_parse_entities/main.cc | 84 +++++++++++++++++++------------
examples/dom_parser/example.dtd | 5 +-
examples/dom_parser/main.cc | 56 +++++++++-----------
libxml++/Makefile.am | 2 +
libxml++/document.cc | 17 ++++++
libxml++/document.h | 18 ++++++-
libxml++/libxml++.h | 1 +
libxml++/nodes/element.cc | 30 ++++++++++-
libxml++/nodes/element.h | 31 +++++++++++-
libxml++/nodes/entitydeclaration.cc | 44 ++++++++++++++++
libxml++/nodes/entitydeclaration.h | 54 ++++++++++++++++++++
libxml++/nodes/entityreference.h | 12 +++--
libxml++/nodes/node.cc | 39 ++++++++++----
19 files changed, 361 insertions(+), 92 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 32b6352..e84c148 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,35 @@
2012-02-15 Kjell Ahlstedt <kjell ahlstedt bredband net>
+ Improved handling of entity references and processing instructions.
+
+ * libxml++/nodes/entitydeclaration.[h|cc]: New files.
+ * Makefile.am:
+ * libxml++/Makefile.am: Add the new files.
+ * libxml++/libxml++.h: Add the new .h file.
+ * docs/manual/libxml++_without_code.xml: Add EntityDeclaration in the list
+ of node classes.
+ * libxml++/document.[h|cc]: Add add_processing_instruction().
+ * libxml++/nodes/element.[h|cc]: Add add_child_entity_reference() and
+ add_child_processing_instruction().
+ * libxml++/nodes/entityreference.h: Improve the description of
+ get_resolved_text() and get_original_text().
+ * libxml++/nodes/node.cc: get_namespace_prefix() and get_namespace_uri():
+ XML_ENTITY_DECL has no namespace. Don't try to find it.
+ create_wrapper(): Create an EntityDeclaration when type == XML_ENTITY_DECL.
+ free_wrappers(): Don't walk the child list when type == XML_ENTITY_REF_NODE.
+ * examples/dom_build/main.cc: Add entity declarations and references, and
+ processing instructions to the built xml file.
+ * examples/dom_parse_entities/example.dtd: Make it compatible with example.xml.
+ * examples/dom_parse_entities/example.xml: Add an entity definition that
+ contains entity references.
+ * examples/dom_parse_entities/main.cc: Print the parsed file both with and
+ without entity substitution.
+ * examples/dom_parser/example.dtd: Make it compatible with example.xml.
+ * examples/dom_parser/main.cc: Add command flag -E (Don't substitute entities).
+ Bug #669481
+
+2012-02-15 Kjell Ahlstedt <kjell ahlstedt bredband net>
+
Add some files to .gitignore.
* .gitignore: Add docs files that are copied from mm-common.
diff --git a/Makefile.am b/Makefile.am
index 4458317..5b76b34 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -53,6 +53,7 @@ h_nodes_sources_public = libxml++/nodes/cdatanode.h \
libxml++/nodes/commentnode.h \
libxml++/nodes/contentnode.h \
libxml++/nodes/element.h \
+ libxml++/nodes/entitydeclaration.h \
libxml++/nodes/entityreference.h \
libxml++/nodes/node.h \
libxml++/nodes/processinginstructionnode.h \
@@ -88,6 +89,7 @@ cc_sources = libxml++/attribute.cc \
libxml++/nodes/cdatanode.cc \
libxml++/nodes/commentnode.cc \
libxml++/nodes/contentnode.cc \
+ libxml++/nodes/entitydeclaration.cc \
libxml++/nodes/entityreference.cc \
libxml++/nodes/element.cc \
libxml++/nodes/node.cc \
diff --git a/docs/manual/libxml++_without_code.xml b/docs/manual/libxml++_without_code.xml
index 62b988e..c30a885 100644
--- a/docs/manual/libxml++_without_code.xml
+++ b/docs/manual/libxml++_without_code.xml
@@ -91,6 +91,7 @@ url="http://libxmlplusplus.sourceforge.net">libxmlplusplus.sourceforge.net</ulin
<itemizedlist>
<listitem><para>xmlpp::CdataNode</para></listitem>
<listitem><para>xmlpp::CommentNode</para></listitem>
+ <listitem><para>xmlpp::EntityDeclaration</para></listitem>
<listitem><para>xmlpp::ProcessingInstructionNode</para></listitem>
<listitem><para>xmlpp::TextNode</para></listitem>
</itemizedlist>
@@ -103,7 +104,7 @@ url="http://libxmlplusplus.sourceforge.net">libxmlplusplus.sourceforge.net</ulin
</itemizedlist>
</para>
- <para>Although you may obtain pointers to the <literal>Node</literal>s, these <literal>Node</literal>s are always owned by their parent Nodes. In most cases that means that the Node will exist, and your pointer will be valid, as long as the <literal>Document</literal> instance exists.</para>
+ <para>Although you may obtain pointers to the <literal>Node</literal>s, these <literal>Node</literal>s are always owned by their parent <literal>Node</literal>. In most cases that means that the <literal>Node</literal> will exist, and your pointer will be valid, as long as the <literal>Document</literal> instance exists.</para>
<para>There are also several methods which can create new child <literal>Node</literal>s. By using these, and one of the <literal>Document::write_*()</literal> methods, you can use libxml++ to build a new XML document.</para>
diff --git a/examples/dom_build/main.cc b/examples/dom_build/main.cc
index 82cdc0b..1ed3090 100644
--- a/examples/dom_build/main.cc
+++ b/examples/dom_build/main.cc
@@ -24,10 +24,8 @@
#endif
#include <libxml++/libxml++.h>
-
#include <iostream>
-
int
main(int /* argc */, char** /* argv */)
{
@@ -41,11 +39,16 @@ main(int /* argc */, char** /* argv */)
#endif //LIBXMLCPP_EXCEPTIONS_ENABLED
xmlpp::Document document;
document.set_internal_subset("example_xml_doc", "", "example_xml_doc.dtd");
+ document.set_entity_declaration("example1", xmlpp::XML_INTERNAL_GENERAL_ENTITY,
+ "", "example_xml_doc.dtd", "Entity content");
+ document.add_processing_instruction("application1", "This is an example document");
+ document.add_comment("First comment");
//foo is the default namespace prefix.
xmlpp::Element* nodeRoot = document.create_root_node("exampleroot", "http://foo", "foo"); //Declares the namespace and uses its prefix for this node
nodeRoot->set_namespace_declaration("http://foobar", "foobar"); //Also associate this prefix with this namespace:
+ nodeRoot->set_child_text("\n");
xmlpp::Element* nodeChild = nodeRoot->add_child("examplechild");
//Associate prefix with namespace:
@@ -53,8 +56,13 @@ main(int /* argc */, char** /* argv */)
nodeChild->set_namespace("bar"); //So it will be bar::examplechild.
nodeChild->set_attribute("id", "1", "foo"); //foo is the namespace prefix. You could also just use a name of foo:id".
- nodeChild->set_child_text("Some content");
+ nodeChild->set_child_text("\nSome content\n");
nodeChild->add_child_comment("Some comments");
+ nodeChild->add_child_entity_reference("example1");
+ nodeChild->add_child_entity_reference("#x20ac"); // â
+ nodeChild->add_child_text("\n");
+ nodeChild->add_child_processing_instruction("application1", "This is an example node");
+ nodeChild->add_child_text("\n");
nodeChild->add_child("child_of_child", "bar");
nodeChild = nodeRoot->add_child("examplechild", "foobar"); //foobar is the namespace prefix
@@ -62,7 +70,7 @@ main(int /* argc */, char** /* argv */)
Glib::ustring whole = document.write_to_string();
std::cout << "XML built at runtime: " << std::endl << whole << std::endl;
- std::cout << "default namespace: " << nodeRoot->get_namespace_uri() << std::endl;
+ std::cout << "namespace of root node: " << nodeRoot->get_namespace_uri() << std::endl;
#ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
}
catch(const std::exception& ex)
diff --git a/examples/dom_parse_entities/example.dtd b/examples/dom_parse_entities/example.dtd
index 925f074..3d5c32f 100644
--- a/examples/dom_parse_entities/example.dtd
+++ b/examples/dom_parse_entities/example.dtd
@@ -5,7 +5,7 @@ DTD for libxml++ example.
<!ELEMENT example (examplechild)+ >
-<!ELEMENT examplechild (child_of_child)+ >
+<!ELEMENT examplechild (#PCDATA | child_of_child)* >
<!ATTLIST examplechild
id CDATA #REQUIRED
>
diff --git a/examples/dom_parse_entities/example.xml b/examples/dom_parse_entities/example.xml
index b8c97ad..93d4a4c 100644
--- a/examples/dom_parse_entities/example.xml
+++ b/examples/dom_parse_entities/example.xml
@@ -2,6 +2,11 @@
<!DOCTYPE example PUBLIC "" "example.dtd" [
<!ENTITY wwwmurrayc "http://www.murrayc.com">
<!ENTITY wwwlibxmlplusplus "http://libxmlplusplus.sourceforge.net">
+<!ENTITY mercury "☿">
+<!ENTITY venus "♀">
+<!ENTITY earth "♁">
+<!ENTITY mars "♂">
+<!ENTITY planets "&mercury;(☿), &venus;(♀), &earth;(♁), &mars;(♂)">
]>
<example>
@@ -9,6 +14,8 @@
Some content. &wwwmurrayc;
Some other content &wwwlibxmlplusplus;
<child_of_child/>
+ Mercury &mercury;
+ Some planets &planets;
</examplechild>
</example>
diff --git a/examples/dom_parse_entities/main.cc b/examples/dom_parse_entities/main.cc
index 9a326a4..b0c47ff 100644
--- a/examples/dom_parse_entities/main.cc
+++ b/examples/dom_parse_entities/main.cc
@@ -27,25 +27,31 @@
#include <iostream>
-void print_indentation(unsigned int indentation)
-{
- for(unsigned int i = 0; i < indentation; ++i)
- std::cout << " ";
-}
-
-void print_node(const xmlpp::Node* node, unsigned int indentation = 0)
+void print_node(const xmlpp::Node* node, bool substitute_entities, unsigned int indentation = 0)
{
+ const Glib::ustring indent(indentation, ' ');
std::cout << std::endl; //Separate nodes by an empty line.
-
- const xmlpp::EntityReference* nodeEntityReference = dynamic_cast<const xmlpp::EntityReference*>(node);
- if(nodeEntityReference)
+ if (substitute_entities)
{
- print_indentation(indentation);
- std::cout << "entity reference name = " << nodeEntityReference->get_name() << std::endl;
- std::cout << " resolved text = " << nodeEntityReference->get_resolved_text() << std::endl;
- std::cout << " original text = " << nodeEntityReference->get_original_text() << std::endl;
+ // Entities have been substituted. Print the text nodes.
+ const xmlpp::TextNode* nodeText = dynamic_cast<const xmlpp::TextNode*>(node);
+ if (nodeText && !nodeText->is_white_space())
+ {
+ std::cout << indent << "text = " << nodeText->get_content() << std::endl;
+ }
}
+ else
+ {
+ // Entities have not been substituted. Print the entity reference nodes.
+ const xmlpp::EntityReference* nodeEntityReference = dynamic_cast<const xmlpp::EntityReference*>(node);
+ if (nodeEntityReference)
+ {
+ std::cout << indent << "entity reference name = " << nodeEntityReference->get_name() << std::endl;
+ std::cout << indent << " resolved text = " << nodeEntityReference->get_resolved_text() << std::endl;
+ std::cout << indent << " original text = " << nodeEntityReference->get_original_text() << std::endl;
+ }
+ } // end if (substitute_entities)
const xmlpp::ContentNode* nodeContent = dynamic_cast<const xmlpp::ContentNode*>(node);
if(!nodeContent)
@@ -54,7 +60,7 @@ void print_node(const xmlpp::Node* node, unsigned int indentation = 0)
xmlpp::Node::NodeList list = node->get_children();
for(xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter)
{
- print_node(*iter, indentation + 2); //recursive
+ print_node(*iter, substitute_entities, indentation + 2); //recursive
}
}
}
@@ -71,27 +77,41 @@ int main(int argc, char* argv[])
else
filepath = "example.xml";
- #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
- try
+ // Parse first without, then with, entity substitution.
+ bool substitute_entities = false;
+ while (true)
{
- #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
- xmlpp::DomParser parser;
- //parser.set_validate();
- parser.set_substitute_entities(false);
- parser.parse_file(filepath);
- if(parser)
+ if (substitute_entities)
+ std::cout << std::endl << "<<< With entity substitution >>>" << std::endl;
+ else
+ std::cout << std::endl << "<<< Without entity substitution >>>" << std::endl;
+
+ #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
+ try
{
- //Walk the tree:
- const xmlpp::Node* pNode = parser.get_document()->get_root_node(); //deleted by DomParser.
- print_node(pNode);
+ #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
+ xmlpp::DomParser parser;
+ parser.set_validate();
+ parser.set_substitute_entities(substitute_entities);
+ parser.parse_file(filepath);
+ if(parser)
+ {
+ //Walk the tree:
+ const xmlpp::Node* pNode = parser.get_document()->get_root_node(); //deleted by DomParser.
+ print_node(pNode, substitute_entities);
+ }
+ #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
}
- #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
- }
- catch(const std::exception& ex)
- {
- std::cout << "Exception caught: " << ex.what() << std::endl;
+ catch(const std::exception& ex)
+ {
+ std::cout << "Exception caught: " << ex.what() << std::endl;
+ }
+ #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
+
+ if (substitute_entities) break;
+
+ substitute_entities = true;
}
- #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
return 0;
}
diff --git a/examples/dom_parser/example.dtd b/examples/dom_parser/example.dtd
index 925f074..b21ed41 100644
--- a/examples/dom_parser/example.dtd
+++ b/examples/dom_parser/example.dtd
@@ -3,12 +3,13 @@
DTD for libxml++ example.
-->
-<!ELEMENT example (examplechild)+ >
+<!ELEMENT example (examplechild | examplechildtext)+ >
<!ELEMENT examplechild (child_of_child)+ >
<!ATTLIST examplechild
- id CDATA #REQUIRED
+ id CDATA #REQUIRED
>
<!ELEMENT child_of_child EMPTY >
+<!ELEMENT examplechildtext (#PCDATA) >
diff --git a/examples/dom_parser/main.cc b/examples/dom_parser/main.cc
index 3508216..5929ce3 100644
--- a/examples/dom_parser/main.cc
+++ b/examples/dom_parser/main.cc
@@ -27,14 +27,9 @@
#include <iostream>
-void print_indentation(unsigned int indentation)
-{
- for(unsigned int i = 0; i < indentation; ++i)
- std::cout << " ";
-}
-
void print_node(const xmlpp::Node* node, unsigned int indentation = 0)
{
+ const Glib::ustring indent(indentation, ' ');
std::cout << std::endl; //Separate nodes by an empty line.
const xmlpp::ContentNode* nodeContent = dynamic_cast<const xmlpp::ContentNode*>(node);
@@ -48,62 +43,55 @@ void print_node(const xmlpp::Node* node, unsigned int indentation = 0)
if(!nodeText && !nodeComment && !nodename.empty()) //Let's not say "name: text".
{
- print_indentation(indentation);
-
const Glib::ustring namespace_prefix = node->get_namespace_prefix();
- if(namespace_prefix.empty())
- std::cout << "Node name = " << nodename << std::endl;
- else
- std::cout << "Node name = " << namespace_prefix << ":" << nodename << std::endl;
+
+ std::cout << indent << "Node name = ";
+ if(!namespace_prefix.empty())
+ std::cout << namespace_prefix << ":";
+ std::cout << nodename << std::endl;
}
else if(nodeText) //Let's say when it's text. - e.g. let's say what that white space is.
{
- print_indentation(indentation);
- std::cout << "Text Node" << std::endl;
+ std::cout << indent << "Text Node" << std::endl;
}
//Treat the various node types differently:
if(nodeText)
{
- print_indentation(indentation);
- std::cout << "text = \"" << nodeText->get_content() << "\"" << std::endl;
+ std::cout << indent << "text = \"" << nodeText->get_content() << "\"" << std::endl;
}
else if(nodeComment)
{
- print_indentation(indentation);
- std::cout << "comment = " << nodeComment->get_content() << std::endl;
+ std::cout << indent << "comment = " << nodeComment->get_content() << std::endl;
}
else if(nodeContent)
{
- print_indentation(indentation);
- std::cout << "content = " << nodeContent->get_content() << std::endl;
+ std::cout << indent << "content = " << nodeContent->get_content() << std::endl;
}
else if(const xmlpp::Element* nodeElement = dynamic_cast<const xmlpp::Element*>(node))
{
//A normal Element node:
//line() works only for ElementNodes.
- print_indentation(indentation);
- std::cout << " line = " << node->get_line() << std::endl;
+ std::cout << indent << " line = " << node->get_line() << std::endl;
//Print attributes:
const xmlpp::Element::AttributeList& attributes = nodeElement->get_attributes();
for(xmlpp::Element::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
{
const xmlpp::Attribute* attribute = *iter;
- print_indentation(indentation);
-
const Glib::ustring namespace_prefix = attribute->get_namespace_prefix();
- if(namespace_prefix.empty())
- std::cout << " Attribute " << attribute->get_name() << " = " << attribute->get_value() << std::endl;
- else
- std::cout << " Attribute " << namespace_prefix << ":" << attribute->get_name() << " = " << attribute->get_value() << std::endl;
+
+ std::cout << indent << " Attribute ";
+ if(!namespace_prefix.empty())
+ std::cout << namespace_prefix << ":";
+ std::cout << attribute->get_name() << " = " << attribute->get_value() << std::endl;
}
const xmlpp::Attribute* attribute = nodeElement->get_attribute("title");
if(attribute)
{
- std::cout << "title found: =" << attribute->get_value() << std::endl;
+ std::cout << indent << "title = " << attribute->get_value() << std::endl;
}
}
@@ -127,6 +115,7 @@ int main(int argc, char* argv[])
bool validate = false;
bool set_throw_messages = false;
bool throw_messages = false;
+ bool substitute_entities = true;
int argi = 1;
while (argc > argi && *argv[argi] == '-') // option
@@ -144,11 +133,15 @@ int main(int argc, char* argv[])
set_throw_messages = true;
throw_messages = false;
break;
+ case 'E':
+ substitute_entities = false;
+ break;
default:
std::cout << "Usage: " << argv[0] << " [-v] [-t] [-e] [filename]" << std::endl
<< " -v Validate" << std::endl
<< " -t Throw messages in an exception" << std::endl
- << " -e Write messages to stderr" << std::endl;
+ << " -e Write messages to stderr" << std::endl
+ << " -E Do not substitute entities" << std::endl;
return 1;
}
argi++;
@@ -168,7 +161,8 @@ int main(int argc, char* argv[])
parser.set_validate();
if (set_throw_messages)
parser.set_throw_messages(throw_messages);
- parser.set_substitute_entities(); //We just want the text to be resolved/unescaped automatically.
+ //We can have the text resolved/unescaped automatically.
+ parser.set_substitute_entities(substitute_entities);
parser.parse_file(filepath);
if(parser)
{
diff --git a/libxml++/Makefile.am b/libxml++/Makefile.am
index e511103..091ce26 100644
--- a/libxml++/Makefile.am
+++ b/libxml++/Makefile.am
@@ -20,6 +20,7 @@ h_sources_public = libxml++.h \
nodes/commentnode.h \
nodes/contentnode.h \
nodes/element.h \
+ nodes/entitydeclaration.h \
nodes/entityreference.h \
nodes/node.h \
nodes/processinginstructionnode.h \
@@ -48,6 +49,7 @@ cc_sources = attribute.cc \
nodes/cdatanode.cc \
nodes/commentnode.cc \
nodes/contentnode.cc \
+ nodes/entitydeclaration.cc \
nodes/entityreference.cc \
nodes/element.cc \
nodes/node.cc \
diff --git a/libxml++/document.cc b/libxml++/document.cc
index 0be6a67..03e6996 100644
--- a/libxml++/document.cc
+++ b/libxml++/document.cc
@@ -175,6 +175,23 @@ CommentNode* Document::add_comment(const Glib::ustring& content)
return static_cast<CommentNode*>(node->_private);
}
+ProcessingInstructionNode* Document::add_processing_instruction(
+ const Glib::ustring& name, const Glib::ustring& content)
+{
+ xmlNode* node = xmlNewDocPI(impl_, (const xmlChar*)name.c_str(), (const xmlChar*)content.c_str());
+ if(!node)
+ {
+ #ifdef LIBXMLCPP_EXCEPTIONS_ENABLED
+ throw internal_error("Cannot create processing instruction node");
+ #else
+ return 0;
+ #endif //LIBXMLCPP_EXCEPTIONS_ENABLED
+ }
+ node = xmlAddChild((xmlNode*)impl_, node);
+ Node::create_wrapper(node);
+ return node ? static_cast<ProcessingInstructionNode*>(node->_private) : 0;
+}
+
void Document::write_to_file(const Glib::ustring& filename, const Glib::ustring& encoding)
{
do_write_to_file(filename, encoding, false);
diff --git a/libxml++/document.h b/libxml++/document.h
index d8a66fb..5c2e50e 100644
--- a/libxml++/document.h
+++ b/libxml++/document.h
@@ -42,7 +42,7 @@ class Document;
//TODO: Make Document inherit from Node, when we can break ABI one day?
//
//libxml might intend xmlDoc to derive (theoretically) from xmlNode.
-//This is suggested because the XmlNodeSet returned by xmlXPathEval (see the Node::find() implementation) can contain either xmlNode or xmlDocument elements.
+//This is suggested because the xmlNodeSet returned by xmlXPathEval (see the Node::find() implementation) can contain either xmlNode or xmlDocument elements.
/**
* Represents an XML document in the DOM model.
*/
@@ -88,7 +88,7 @@ public:
/** Creates the root node.
* @param name The node's name.
- * @param ns_uri The namespace URI. A namspace declaration will be added to this node, because it could not have
+ * @param ns_uri The namespace URI. A namespace declaration will be added to this node, because it could not have
been declared before.
* @param ns_prefix The namespace prefix to associate with the namespace. If no namespace prefix is specified then
the namespace URI will be the default namespace.
@@ -112,6 +112,18 @@ public:
*/
CommentNode* add_comment(const Glib::ustring& content);
+ /** Append a new processing instruction node.
+ *
+ * @newin{2,36}
+ *
+ * @param name The name of the application to which the instruction is directed.
+ * @param content The content of the instruction. This should be unescaped - see ContentNode::set_content().
+ * @returns The new processing instruction node.
+ * @throws internal_error
+ */
+ ProcessingInstructionNode* add_processing_instruction(
+ const Glib::ustring& name, const Glib::ustring& content);
+
//TODO: Use std::string for filenames.
/** Write the document to a file.
* @param filename
@@ -178,7 +190,7 @@ public:
protected:
/** Retrieve an Entity.
* The entity can be from an external subset or internally declared.
- * @param name Then name of the entity to get.
+ * @param name The name of the entity to get.
* @returns A pointer to the libxml2 entity structure.
*/
_xmlEntity* get_entity(const Glib::ustring& name);
diff --git a/libxml++/libxml++.h b/libxml++/libxml++.h
index 95184ed..6f630a7 100644
--- a/libxml++/libxml++.h
+++ b/libxml++/libxml++.h
@@ -55,6 +55,7 @@
#include <libxml++/nodes/node.h>
#include <libxml++/nodes/commentnode.h>
#include <libxml++/nodes/element.h>
+#include <libxml++/nodes/entitydeclaration.h>
#include <libxml++/nodes/entityreference.h>
#include <libxml++/nodes/textnode.h>
#include <libxml++/attribute.h>
diff --git a/libxml++/nodes/element.cc b/libxml++/nodes/element.cc
index a798814..809eaa3 100644
--- a/libxml++/nodes/element.cc
+++ b/libxml++/nodes/element.cc
@@ -5,7 +5,6 @@
*/
#include <libxml++/nodes/element.h>
-#include <libxml++/nodes/textnode.h>
#include <libxml++/exceptions/internal_error.h>
#include <libxml++/document.h>
@@ -247,7 +246,6 @@ CommentNode* Element::add_child_comment(const Glib::ustring& content)
}
-
CdataNode* Element::add_child_cdata(const Glib::ustring& content)
{
xmlNode* node = xmlNewCDataBlock(cobj()->doc, (const xmlChar*)content.c_str(), content.bytes());
@@ -256,5 +254,33 @@ CdataNode* Element::add_child_cdata(const Glib::ustring& content)
return static_cast<CdataNode*>(node->_private);
}
+EntityReference* Element::add_child_entity_reference(const Glib::ustring& name)
+{
+ const Glib::ustring extended_name = name + " "; // This is at least two chars long.
+ int ichar = 0;
+ if (extended_name[ichar] == '&')
+ ++ichar;
+
+ // Is it an entity reference or a character reference?
+ // libxml uses xmlNode::type == XML_ENTITY_REF_NODE for both.
+ xmlNode* node = 0;
+ if (extended_name[ichar] == '#')
+ node = xmlNewCharRef(cobj()->doc, (const xmlChar*)name.c_str());
+ else
+ node = xmlNewReference(cobj()->doc, (const xmlChar*)name.c_str());
+ node = xmlAddChild(cobj(), node);
+ Node::create_wrapper(node);
+ return node ? static_cast<EntityReference*>(node->_private) : 0;
+}
+
+ProcessingInstructionNode* Element::add_child_processing_instruction(
+ const Glib::ustring& name, const Glib::ustring& content)
+{
+ xmlNode* node = xmlNewDocPI(cobj()->doc, (const xmlChar*)name.c_str(), (const xmlChar*)content.c_str());
+ node = xmlAddChild(cobj(), node);
+ Node::create_wrapper(node);
+ return node ? static_cast<ProcessingInstructionNode*>(node->_private) : 0;
+}
+
} //namespace xmlpp
diff --git a/libxml++/nodes/element.h b/libxml++/nodes/element.h
index e72b235..da46d4c 100644
--- a/libxml++/nodes/element.h
+++ b/libxml++/nodes/element.h
@@ -11,6 +11,9 @@
#include <libxml++/attribute.h>
#include <libxml++/nodes/commentnode.h>
#include <libxml++/nodes/cdatanode.h>
+#include <libxml++/nodes/textnode.h>
+#include <libxml++/nodes/processinginstructionnode.h>
+#include <libxml++/nodes/entityreference.h>
namespace xmlpp
{
@@ -45,7 +48,7 @@ public:
//See the patch at https://bugzilla.gnome.org/show_bug.cgi?id=632524
// FIXME: the following only returns explicitely provided
// attributes, not default ones declared in the dtd.
- // TOOD: Is this still true? murrayc
+ // TODO: Is this still true? murrayc
Attribute* get_attribute(const Glib::ustring& name,
const Glib::ustring& ns_prefix = Glib::ustring()) const;
@@ -141,6 +144,32 @@ public:
*/
CdataNode* add_child_cdata(const Glib::ustring& content);
+ /** Append a new entity reference node.
+ * The reference can be either an entity reference ("name" or "&name;") or
+ * a character reference ("#dec", "#xhex", "&#dec;", or "&#xhex;").
+ *
+ * '&' and ';' are optional. If they exist, they are stripped from the stored
+ * copy of the name. Node::get_name() returns the name without '&' and ';'.
+ * If the Document is written to an XML file, '&' and ';' are written.
+ *
+ * @newin{2,36}
+ *
+ * @param name The name of the entity.
+ * @returns The new entity reference node.
+ */
+ EntityReference* add_child_entity_reference(const Glib::ustring& name);
+
+ /** Append a new processing instruction node.
+ *
+ * @newin{2,36}
+ *
+ * @param name The name of the application to which the instruction is directed.
+ * @param content The content of the instruction. This should be unescaped - see ContentNode::set_content().
+ * @returns The new processing instruction node.
+ */
+ ProcessingInstructionNode* add_child_processing_instruction(
+ const Glib::ustring& name, const Glib::ustring& content);
+
protected:
Glib::ustring get_namespace_uri_for_prefix(const Glib::ustring& ns_prefix) const;
};
diff --git a/libxml++/nodes/entitydeclaration.cc b/libxml++/nodes/entitydeclaration.cc
new file mode 100644
index 0000000..9486cb4
--- /dev/null
+++ b/libxml++/nodes/entitydeclaration.cc
@@ -0,0 +1,44 @@
+/* entitydeclaration.cc
+ * libxml++ and this file are copyright (C) 2000 by Ari Johnson, and
+ * are covered by the GNU Lesser General Public License, which should be
+ * included with libxml++ as the file COPYING.
+ */
+
+#include <libxml++/nodes/entitydeclaration.h>
+#include <libxml/tree.h>
+
+namespace xmlpp
+{
+
+EntityDeclaration::EntityDeclaration(xmlNode* node)
+: ContentNode(node)
+{}
+
+EntityDeclaration::~EntityDeclaration()
+{}
+
+Glib::ustring EntityDeclaration::get_resolved_text() const
+{
+ return cobj()->content ? (const char*)cobj()->content : "";
+}
+
+Glib::ustring EntityDeclaration::get_original_text() const
+{
+ return cobj()->orig ? (const char*)cobj()->orig : "";
+}
+
+xmlEntity* EntityDeclaration::cobj()
+{
+ // An XML_ENTITY_DECL is represented by an xmlEntity struct. Reinterpret
+ // the xmlNode pointer stored in the base class as an xmlEntity pointer.
+ return reinterpret_cast<xmlEntity*>(Node::cobj());
+}
+
+const xmlEntity* EntityDeclaration::cobj() const
+{
+ // An XML_ENTITY_DECL is represented by an xmlEntity struct. Reinterpret
+ // the xmlNode pointer stored in the base class as an xmlEntity pointer.
+ return reinterpret_cast<const xmlEntity*>(Node::cobj());
+}
+
+} //namespace xmlpp
diff --git a/libxml++/nodes/entitydeclaration.h b/libxml++/nodes/entitydeclaration.h
new file mode 100644
index 0000000..f5f4a35
--- /dev/null
+++ b/libxml++/nodes/entitydeclaration.h
@@ -0,0 +1,54 @@
+/* entitydeclaration.h
+ * libxml++ and this file are copyright (C) 2000 by Ari Johnson, and
+ * are covered by the GNU Lesser General Public License, which should be
+ * included with libxml++ as the file COPYING.
+ */
+
+#ifndef __LIBXMLPP_NODES_ENTITYDECLARATION_H
+#define __LIBXMLPP_NODES_ENTITYDECLARATION_H
+
+#include <libxml++/nodes/contentnode.h>
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+extern "C" {
+ struct _xmlEntity;
+}
+#endif //#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+namespace xmlpp
+{
+
+/** Entity declaration. This will be instantiated by the parser.
+ *
+ * @newin{2,36}
+ *
+ */
+class EntityDeclaration : public ContentNode
+{
+public:
+ explicit EntityDeclaration(_xmlNode* node);
+ virtual ~EntityDeclaration();
+
+ /** Get the text with character references (like "ß") resolved.
+ * If the entity declaration does not contain any reference to another entity,
+ * this is the text that an entity reference would have resolved to, if the XML
+ * document had been parsed with Parser::set_substitute_entities(true).
+ * @returns The text with character references unescaped.
+ */
+ Glib::ustring get_resolved_text() const;
+
+ /** Get the text as read from the XML or DTD file.
+ * @returns The escaped text.
+ */
+ Glib::ustring get_original_text() const;
+
+ ///Access the underlying libxml implementation.
+ _xmlEntity* cobj();
+
+ ///Access the underlying libxml implementation.
+ const _xmlEntity* cobj() const;
+};
+
+} // namespace xmlpp
+
+#endif //__LIBXMLPP_NODES_ENTITYDECLARATION_H
diff --git a/libxml++/nodes/entityreference.h b/libxml++/nodes/entityreference.h
index d9d935f..f0d0495 100644
--- a/libxml++/nodes/entityreference.h
+++ b/libxml++/nodes/entityreference.h
@@ -20,13 +20,17 @@ public:
explicit EntityReference(_xmlNode* node);
virtual ~EntityReference();
- /** Get the text to which this entity reference would have resolved if the XML document had been parsed with Parser::set_substitute_entities(true).
- * @returns The unescaped text.
+ /** Get the text with character references (like "ß") resolved.
+ * If the corresponding entity declaration does not contain any reference to
+ * another entity, this is the text that the reference would have resolved to
+ * if the XML document had been parsed with Parser::set_substitute_entities(true).
+ * @returns The text with character references unescaped.
*/
Glib::ustring get_resolved_text() const;
- //TODO: I'm not sure what this is. So far it seems to be the same as get_resolved_text().
- // Maybe it's for nested entity declarations, though I don't know if that is even possile. murrayc.
+ /** Get the text as read from the XML or DTD file.
+ * @returns The escaped text.
+ */
Glib::ustring get_original_text() const;
};
diff --git a/libxml++/nodes/node.cc b/libxml++/nodes/node.cc
index bc56266..36494a4 100644
--- a/libxml++/nodes/node.cc
+++ b/libxml++/nodes/node.cc
@@ -6,6 +6,7 @@
#include <libxml++/nodes/element.h>
#include <libxml++/nodes/node.h>
+#include <libxml++/nodes/entitydeclaration.h>
#include <libxml++/nodes/entityreference.h>
#include <libxml++/nodes/textnode.h>
#include <libxml++/nodes/commentnode.h>
@@ -350,13 +351,14 @@ NodeSet Node::find(const Glib::ustring& xpath,
Glib::ustring Node::get_namespace_prefix() const
{
- if(impl_->type == XML_DOCUMENT_NODE)
+ if(impl_->type == XML_DOCUMENT_NODE || impl_->type == XML_ENTITY_DECL)
{
- //impl_ is actually of type xmlDoc, instead of just xmlNode.
- //libxml does not always use GObject-style inheritance, so xmlDoc does not have all the same struct fields as xmlNode.
+ //impl_ is actually of type xmlDoc or xmlEntity, instead of just xmlNode.
+ //libxml does not always use GObject-style inheritance, so xmlDoc and
+ //xmlEntity do not have all the same struct fields as xmlNode.
//Therefore, a call to impl_->ns would be invalid.
//This can be an issue when calling this method on a Node returned by Node::find().
- //See the TODO comment on Document, suggesting that Document should derived from Node.
+ //See the TODO comment on Document, suggesting that Document should derive from Node.
return Glib::ustring();
}
@@ -369,10 +371,11 @@ Glib::ustring Node::get_namespace_prefix() const
Glib::ustring Node::get_namespace_uri() const
{
- if(impl_->type == XML_DOCUMENT_NODE)
+ if(impl_->type == XML_DOCUMENT_NODE || impl_->type == XML_ENTITY_DECL)
{
- //impl_ is actually of type xmlDoc, instead of just xmlNode.
- //libxml does not always use GObject-style inheritance, so xmlDoc does not have all the same struct fields as xmlNode.
+ //impl_ is actually of type xmlDoc or xmlEntity, instead of just xmlNode.
+ //libxml does not always use GObject-style inheritance, so xmlDoc and
+ //xmlEntity do not have all the same struct fields as xmlNode.
//Therefore, a call to impl_->ns would be invalid.
//This can be an issue when calling this method on a Node returned by Node::find().
//See the TODO comment on Document, suggesting that Document should derived from Node.
@@ -454,6 +457,11 @@ void Node::create_wrapper(xmlNode* node)
// //node->_private = new xmlpp::ProcessingInstructionNode(node);
// break;
//}
+ case XML_ENTITY_DECL:
+ {
+ node->_private = new xmlpp::EntityDeclaration(node);
+ break;
+ }
case XML_ENTITY_REF_NODE:
{
node->_private = new xmlpp::EntityReference(node);
@@ -468,7 +476,8 @@ void Node::create_wrapper(xmlNode* node)
{
// good default for release versions
node->_private = new xmlpp::Node(node);
- std::cerr << G_STRFUNC << "Warning: new node of unknown type created: " << node->type << std::endl;
+ std::cerr << G_STRFUNC << " Warning: new node of unknown type created: "
+ << node->type << std::endl;
break;
}
}
@@ -479,9 +488,17 @@ void Node::free_wrappers(xmlNode* node)
if(!node)
return;
- //Walk the children list
- for(xmlNode* child=node->children; child; child=child->next)
- free_wrappers(child);
+ //If an entity declaration contains an entity reference, there can be cyclic
+ //references between entity declarations and entity references. (It's not
+ //a tree.) We must avoid an infinite recursion.
+ //Compare xmlFreeNode(), which frees the children of all node types except
+ //XML_ENTITY_REF_NODE.
+ if (node->type != XML_ENTITY_REF_NODE)
+ {
+ //Walk the children list.
+ for (xmlNode* child = node->children; child; child = child->next)
+ free_wrappers(child);
+ }
//Delete the local one
switch(node->type)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]