![]() |
The class zeep::xml::document
derives from zeep::xml::element
can load from and write
to files.
You can use std::iostream to read and write zeep::xml::document
objects. Reading is as simple as:
zeep::xml::document doc; std::cin >> doc;
Writing is just as simple. A warning though, round trip fidelity is not guaranteed.
There are a few issues with that. First of all, the default is to replace
CDATA sections in a file with their content. If this is not the desired behaviour
you can call set_preserve_cdata(true)
.
Another issue is that text nodes containing only white space are present
in documents read from disk while these are absent by default in documents
created on the fly. When writing out XML using iostream
you can specify to wrap and indent a document. But if the document was read
in, the result will have extraneous spacing.
Specifying indentation is BTW done like this:
std::cout << std::setw(2) << doc;
That will indent with two spaces for each level.
This will not validate the XML using the DTD by default. If you do want to
validate and process the DTD, you have to specify where to find this DTD
and other external entities. You can either use set_base_dir
or you can specify
an entity_loader using set_entity_loader
As an example, take the following DTD file
<!ELEMENT foo (bar)> <!ELEMENT bar (#PCDATA)> <!ENTITY hello "Hello, world!">
And an XML document containing
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE foo SYSTEM "sample.dtd"> <foo> <bar>&hello;</bar> </foo>
When we want to see the &hello;
entity replaced with 'Hello,
world!'
as specified in the DTD, we need to provide a way to load
this DTD. To do this, look at the following code. Of course, in this example
a simple call to set_base_dir
would have been sufficient.
#include <filesystem> #include <fstream> #include <zeep/xml/document.hpp> namespace fs = std::filesystem; int main() {auto loader = [] (const std::string& base, const std::string& pubid, const std::string& sysid) -> std::istream* { if (base == "." and pubid.empty() and fs::exists(sysid)) return new std::ifstream(sysid); throw std::invalid_argument("Invalid arguments passed in loader"); };
zeep::xml::document doc; doc.set_entity_loader(loader);
std::ifstream is("sample.xml"); is >> doc; using namespace zeep::xml::literals;
if (doc == R"(<foo><bar>Hello, world!</bar></foo>)"_xml) std::cout << "ok" << std::endl; return 0; }