Commit 09a10ea9 authored by Kjell Ahlstedt's avatar Kjell Ahlstedt

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
parent a770d029
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.
......
......@@ -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 \
......
......@@ -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>
......
......@@ -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)
......
......@@ -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
>
......
......@@ -2,6 +2,11 @@
<!DOCTYPE example PUBLIC "" "example.dtd" [
<!ENTITY wwwmurrayc "http://www.murrayc.com">
<!ENTITY wwwlibxmlplusplus "http://libxmlplusplus.sourceforge.net">
<!ENTITY mercury "&#x263f;">
<!ENTITY venus "&#x2640;">
<!ENTITY earth "&#x2641;">
<!ENTITY mars "&#x2642;">
<!ENTITY planets "&mercury;(&#x263f;), &venus;(&#x2640;), &earth;(&#x2641;), &mars;(&#x2642;)">
]>
<example>
......@@ -9,6 +14,8 @@
Some content. &wwwmurrayc;
Some other content &wwwlibxmlplusplus;
<child_of_child/>
Mercury &mercury;
Some planets &planets;
</examplechild>
</example>
......@@ -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;
}
......
......@@ -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) >
......@@ -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)
{
......
......@@ -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 \
......
......@@ -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);
......
......@@ -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);
......
......@@ -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>
......
......@@ -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
......@@ -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;
};
......
/* 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
/* 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 "&#xdf;") 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
......@@ -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 "&#xdf;") 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;
};
......
......@@ -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