FERS 1.0.0
The Flexible Extensible Radar Simulator
Loading...
Searching...
No Matches
libxml_wrapper.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-only
2//
3// Copyright (c) 2024-present FERS Contributors (see AUTHORS.md).
4//
5// See the GNU GPLv2 LICENSE file in the FERS project root for more information.
6
7/**
8 * @file libxml_wrapper.cpp
9 * @brief Wrapper for managing XML documents and elements using libxml2.
10 */
11
12#include "libxml_wrapper.h"
13
14#include "libxml/encoding.h"
15#include "libxml/parser.h"
16#include "libxml/valid.h"
17#include "libxml/xmlIO.h"
18#include "libxml/xmlschemas.h"
19
20bool XmlDocument::validateWithDtd(const std::span<const unsigned char> dtdData) const
21{
22 xmlDtdPtr dtd =
23 xmlIOParseDTD(nullptr,
24 xmlParserInputBufferCreateMem(reinterpret_cast<const char*>(dtdData.data()),
25 static_cast<int>(dtdData.size()), XML_CHAR_ENCODING_UTF8),
26 XML_CHAR_ENCODING_UTF8);
27 if (!dtd)
28 {
29 throw XmlException("Failed to parse DTD from memory.");
30 }
31
32 const std::unique_ptr<xmlValidCtxt, decltype(&xmlFreeValidCtxt)> validation_ctxt(xmlNewValidCtxt(),
33 xmlFreeValidCtxt);
34 if (!validation_ctxt)
35 {
36 xmlFreeDtd(dtd);
37 throw XmlException("Failed to create validation context.");
38 }
39
40 const bool is_valid = xmlValidateDtd(validation_ctxt.get(), _doc.get(), dtd);
41 xmlFreeDtd(dtd);
42
43 if (!is_valid)
44 {
45 throw XmlException("XML failed DTD validation.");
46 }
47
48 return true;
49}
50
51bool XmlDocument::validateWithXsd(const std::span<const unsigned char> xsdData) const
52{
53 const std::unique_ptr<xmlSchemaParserCtxt, decltype(&xmlSchemaFreeParserCtxt)> schema_parser_ctxt(
54 xmlSchemaNewMemParserCtxt(reinterpret_cast<const char*>(xsdData.data()), static_cast<int>(xsdData.size())),
55 xmlSchemaFreeParserCtxt);
56 if (!schema_parser_ctxt)
57 {
58 throw XmlException("Failed to create schema parser context.");
59 }
60
61 const std::unique_ptr<xmlSchema, decltype(&xmlSchemaFree)> schema(xmlSchemaParse(schema_parser_ctxt.get()),
62 xmlSchemaFree);
63 if (!schema)
64 {
65 throw XmlException("Failed to parse schema from memory.");
66 }
67
68 const std::unique_ptr<xmlSchemaValidCtxt, decltype(&xmlSchemaFreeValidCtxt)> schema_valid_ctxt(
69 xmlSchemaNewValidCtxt(schema.get()), xmlSchemaFreeValidCtxt);
70 if (!schema_valid_ctxt)
71 {
72 throw XmlException("Failed to create schema validation context.");
73 }
74
75 if (const bool is_valid = xmlSchemaValidateDoc(schema_valid_ctxt.get(), _doc.get()) == 0; !is_valid)
76 {
77 throw XmlException("XML failed XSD validation.");
78 }
79
80 return true;
81}
82
83void mergeXmlDocuments(const XmlDocument& mainDoc, const XmlDocument& includedDoc)
84{
85 const XmlElement main_root = mainDoc.getRootElement();
86 const XmlElement included_root = includedDoc.getRootElement();
87
88 for (xmlNodePtr child = included_root.getNode()->children; child; child = child->next)
89 {
90 if (child->type == XML_ELEMENT_NODE)
91 {
92 xmlNodePtr new_node = xmlCopyNode(child, 1);
93 xmlAddChild(main_root.getNode(), new_node);
94 }
95 }
96}
97
99{
100 const XmlElement root = doc.getRootElement();
101
102 while (true)
103 {
104 if (XmlElement include_element = root.childElement("include", 0); include_element.isValid())
105 {
106 xmlUnlinkNode(include_element.getNode());
107 xmlFreeNode(include_element.getNode());
108 }
109 else
110 {
111 break;
112 }
113 }
114}
115
116bool XmlDocument::loadFile(const std::string_view filename)
117{
118 _doc.reset(xmlReadFile(filename.data(), nullptr, 0));
119 return _doc != nullptr;
120}
121
122bool XmlDocument::loadString(const std::string& content)
123{
124 _doc.reset(xmlReadMemory(content.c_str(), static_cast<int>(content.length()), "in_memory.xml", nullptr, 0));
125 return _doc != nullptr;
126}
127
128std::string XmlDocument::dumpToString() const
129{
130 if (!_doc)
131 {
132 LOG(logging::Level::ERROR, "Document is null; Cannot dump to string");
133 return "";
134 }
135 xmlChar* buffer = nullptr;
136 int size = 0;
137 xmlDocDumpFormatMemory(_doc.get(), &buffer, &size, 1);
138 if (!buffer)
139 {
140 LOG(logging::Level::ERROR, "Failed to dump XML document to memory buffer.");
141 return "";
142 }
143 const std::string result(reinterpret_cast<const char*>(buffer), static_cast<size_t>(size));
144 xmlFree(buffer);
145 return result;
146}
Class for managing XML documents.
XmlElement getRootElement() const
Get the root element of the document.
bool loadFile(std::string_view filename)
Load an XML file into the document.
bool validateWithDtd(std::span< const unsigned char > dtdData) const
Validate the document using a DTD.
bool validateWithXsd(std::span< const unsigned char > xsdData) const
Validate the document using an XSD schema.
bool loadString(const std::string &content)
Load an XML document from a string in memory.
std::string dumpToString() const
Dumps the document to a string.
Class representing a node in an XML document.
XmlElement childElement(const std::string_view name="", const unsigned index=0) const noexcept
Retrieve a child element by name and index.
xmlNodePtr getNode() const noexcept
Get the underlying XML node pointer.
Exception class for handling XML-related errors.
void mergeXmlDocuments(const XmlDocument &mainDoc, const XmlDocument &includedDoc)
Merge two XML documents.
void removeIncludeElements(const XmlDocument &doc)
Remove "include" elements from the XML document.
Wrapper for managing XML documents and elements using libxml2.
#define LOG(level,...)
Definition logging.h:19
@ ERROR
Error level for error events.