#include <x/xml/doc.H> #include <x/xml/newdtd.H> auto empty_document=x::xml::doc::create(); lock->create_child()->element({"html"}) ->element({"body"}) ->element({"p"}) ->text("Hello world"); lock->create_internal_dtd("-//W3C//DTD XHTML 1.0 Strict//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"); lock->save_file("filename.html", true);
This example creates the following file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
<p>Hello world</p>
</body>
</html>
A writer lock's
create_internal_dtd
() method adds a
DOCTYPE
declaration to the XML document. The XML document cannot be empty.
create_internal_dtd
() returns a
x::xml::newdtd
,
which is a reference to a reference-counted
object with methods that further modify the document type
declaration.
A reader lock's
get_internal_dtd
() returns a
x::xml::dtd
that represents the existing document's DOCTYPE
declaration.
A writer lock also implements
get_internal_dtd
(), but the writer lock's
version returns
a x::xml::newdtd
.
x::xml::newdtd
's object is a subclass of
x::xml::dtd
's object and inherits all of
x::xml::dtd
's object's methods that provide
access to the DOCTYPE
's definition:
auto dtd=rlock->get_internal_dtd(); if (dtd->exists()) { std::cout << "Name: " << dtd->name() << std::endl << dtd->external_id() << std::endl << dtd->system_id() << std::endl; }
get_internal_dtd
() returns a
x::xml::dtd
or a
x::xml::newdtd
even when the XML
document does not have a DOCTYPE
.
Its exists
() returns a bool
indication whether the DOCTYPE
exists. If so,
name
(),
external_id
(), and
system_id
() indicate the
DOCTYPE
's name, public/external identifier, and the
system identifier.
x::xml::dtd
and
x::xml::newdtd
are
references to a reference-counted objects
that get created by a reader or a writer lock. They each hold an
internal reference on the lock that created them, until all
references to
x::xml::dtd
's or
x::xml::newdtd
's object go out of scope and
it gets destroyed.
Generally, they follow the same thread-safe semantics as their
corresponding locks. Different threads can retrieve and use their own
respective
x::xml::dtd
, but only one thread can use
a given x::xml::dtd
at the same time.
Only one writer lock can exist at the same time, so there's only
one x::xml::newdtd
in existence, and only
one thread can access the x::xml::newdtd
.
At this time, it's possible to call
get_internal_dtd
() a second time which
technically returns
a different x::xml::newdtd
; however for all
practical purposes it's the same underlying object, and only one thread
can use a x::xml::newdtd
, at a time.
There are also analogous
create_external_dtd
() and
get_external_dtd
() methods, for external
DOCTYPE
subsets, but they're not commonly used;
their only purpose is to expose the underlying
libxml object, that's mainly used in
DTD validation.
A writer lock also implements a
remove_internal_dtd
() (and
remove_external_dtd
()),
which removes an XML document's DOCTYPE
.
The object referenced by
x::xml::newdtd
implements several methods that
add custom entity declaration to DOCTYPE
:
auto empty_document=x::xml::doc::create(); empty_document->writelock()->create_child()->element({"html"}) auto wlock=empty_document->writelock(); auto intdtd=wlock ->create_internal_dtd("-//W3C//DTD XHTML 1.0 Strict//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"); intdtd->create_general_entity("XML", "<i>XML</i>"); // ... wlock->save_file("filename.xml");
This results in the following XML document:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" [
<!ENTITY XML "<i>XML</i>">
]>
<html xmlns="http://www.w3.org/1999/xhtml">
....
Custom entities get typically declared in an XML document that gets
saved into a file. When creating the rest of the document (prior
to saving it), use entity
() to insert an
entity reference:
wlock->create_child()->entity("XML");
This inserts the “&XML;” entity reference into the XML document. Using the “noent” option when loading the XML document resolves entity references, the entities get replaced by their contents, in the parsed XML document.
newdtd->create_parsed_entity("ch1", "", "chapter1.xml");
create_parsed_entity
() adds a declaration for
an external
parsed entity. The second parameter is a public identifier,
which is normally an empty string. This example adds
“<!ENTITY ch1 SYSTEM 'chapter1.xml'>” to the
DOCTYPE
declaration.
newdtd->create_unparsed_entity("table1", "", "table1.jpg", "jpg");
create_unparsed_entity
() adds a declaration for
an external
unparsed entity. The second parameter is a public identifier,
which is normally an empty string. This example adds
“<!ENTITY table1 SYSTEM 'table1.jpg' NDATA jpg>”
to the XML document.
std::ostringstream o; for (int i=1; i<10; ++i) { o << "<!ENTITY ch" << i << " SYSTEM \"ch" << i << ".xml\">"; } newdtd->create_internal_parameter_entity("chapters", o.str());
create_internal_parameter_entity
() adds a
declaration for an internal parameter entity. This example adds
“<!ENTITY % chapters '[...]'>” (with a long, messy
string instead of the ellipsis) to the document.
newdtd->create_external_parameter_entity("chapters", "", "chapters.xml");
create_external_parameter_entity
() adds a
declaration for an
external parameter entity. The second parameter is a public
identifier, which is normally an empty string. This example adds
“<!ENTITY % chapters SYSTEM 'chapters.xml'>” to the document.
newdtd->include_parameter_entity("chapters");
This example adds "%chapters;" to the document.