#ifndef DYNAMIC_DEPTH_INTERNAL_XMPMETA_XML_SERIALIZER_IMPL_H_ // NOLINT
#define DYNAMIC_DEPTH_INTERNAL_XMPMETA_XML_SERIALIZER_IMPL_H_ // NOLINT
#include <libxml/tree.h>
#include <string>
#include <unordered_map>
#include "xmpmeta/xml/serializer.h"
namespace dynamic_depth {
namespace xmpmeta {
namespace xml {
// Writes properties, lists, and child nodes into an XML structure.
//
// Usage example:
// std::unordered_map<string, xmlNsPtr> namespaces;
// string device_name("Device");
// string cameras_name("Cameras");
// string camera_name("Camera");
// string audio_name("Audio");
// string image_name("Image");
// PopulateNamespaces(&namespaces);
// DoSerialization();
//
// // Serialization example.
// void DoSerialization() {
// xmlNodePtr device_node = xmlNewNode(nullptr, device_name);
// Serializer device_serializer(namespaces, device_node);
//
// std::unique_ptr<Serializer> cameras_serializer =
// serializer->CreateListSerializer(cameras_name);
// for (XdmCamera *camera : camera_list_) {
// std::unique_ptr<Serializer> camera_serializer =
// cameras_serializer->CreateItemSerializer("Device", camera_name);
// success &= camera->Serialize(camera_serializer.get());
//
// // Serialize Audio.
// std::unique_ptr<Serializer> audio_serializer =
// camera_serializer->CreateSerializer("Camera", audio_name);
// audio_serializer->WriteProperty(camera_name, "Data", audio_data);
// audio_serializer->WriteProperty(camera_name, "Mime", "audio/mp4");
//
// // Serialize Image.
// std::unique_ptr<Serializer> image_serializer =
// camera_serializer->CreateSerializer("Camera", image_name);
// image_serializer->WriteProperty(image_name, "Data", image_data);
// image_serializer->WriteProperty(image_name, "Mime", "image/jpeg");
//
// // Serialize ImagingModel.
// std::unique_ptr<Serializer> imaging_model_serializer =
// camera_serializer->CreateSerializer("Camera", "ImagingModel");
// std::unique_ptr<Serializer> equirect_model_serializer =
// imaging_model_serializer->CreateSerializer("Camera",
// "EquirectModel");
// // Serializer equirect model fields here.
// }
// }
//
// Resulting XML structure:
// /*
// * <Device>
// * <Device:Cameras>
// * <rdf:Seq>
// * <rdf:li>
// * <Device:Camera>
// * <Camera:Audio Audio:Mime="audio/mp4" Audio:Data="DataValue"/>
// * <Camera:Image Image:Mime="image/jpeg" Image:Data="DataValue"/>
// * <Camera:ImagingModel>
// * <Camera:EquirectModel ...properties/>
// * </Camera:ImagingModel>
// * </Device:Camera>
// * </rdf:li>
// * </rdf:Seq>
// * </Device:Cameras>
// * </Device>
// */
//
// // Namespace population example.
// void PopulateNamespaces(std::unordered_map<string, xmlNsPtr>* namespaces) {
// xmlNsPtr device_ns =
// xmlNewNs(nullptr, ToXmlChar("http://ns.xdm.org/photos/1.0/device")
// ToXmlChar(device_name.data()));
// xmlNsPtr camera_ns =
// xmlNewNs(nullptr, ToXmlChar("http://ns.xdm.org/photos/1.0/camera")
// ToXmlChar(camera_name.data()));
// xmlNsPtr audio_ns =
// xmlNewNs(nullptr, ToXmlChar("http://ns.xdm.org/photos/1.0/audio")
// ToXmlChar(audio_name.data()));
// xmlNsPtr image_ns =
// xmlNewNs(nullptr, ToXmlChar("http://ns.xdm.org/photos/1.0/image")
// ToXmlChar(image_name.data()));
// namespaces->insert(device_name, device_ns);
// namespaces->insert(camera_name, camera_ns);
// namespaces->insert(audio_name, audio_ns);
// namespaces->insert(image_name, image_ns);
// }
class SerializerImpl : public Serializer {
public:
// Constructor.
// The prefix map is required if one of the CreateSerializer methods will be
// called on this object. In particular, the RDF namespace must be present in
// the prefix map if CreateItemSerializer or CreateListSerializer will be
// called.
// The namespaces map serves to keep XML namespace creation out of this
// Serializer, to simplify memory management issues. Note that the libxml
// xmlDocPtr will own all namespace and node pointers.
// The namespaces parameter is a map of node names to full namespaces.
// This contains all the namespaces (nodes and properties) that will be used
// in serialization.
// The node parameter is the caller node. This will be the node in which
// serialization takes place in WriteProperties.
SerializerImpl(const std::unordered_map<string, xmlNsPtr>& namespaces,
xmlNodePtr node);
// Returns a new Serializer for an object that is part of an rdf:Seq list
// of objects.
// The parent serializer must be created with CreateListSerializer.
std::unique_ptr<Serializer> CreateItemSerializer(
const string& prefix, const string& item_name) const override;
// Returns a new Serializer for a list of objects that correspond to an
// rdf:Seq XML node, where each object is to be serialized as a child node of
// every rdf:li node in the list.
// The serializer is created on an rdf:Seq node, which is the child of a
// newly created XML node with the name list_name.
std::unique_ptr<Serializer> CreateListSerializer(
const string& prefix, const string& list_name) const override;
// Creates a serializer from the current serializer.
// @param node_name The name of the caller node. This will be the parent of
// any new nodes or properties set by this serializer.
std::unique_ptr<Serializer> CreateSerializer(
const string& node_ns_name, const string& node_name) const override;
// Writes the property into the current node, prefixed with prefix if it
// has a corresponding namespace href in namespaces_, fails otherwise.
// Returns true if serialization is successful.
// If prefix is empty, the property will not be set on an XML namespace.
// name must not be empty.
// value may be empty.
bool WriteBoolProperty(const string& prefix, const string& name,
bool value) const override;
bool WriteProperty(const string& prefix, const string& name,
const string& value) const override;
// Writes the collection of numbers into a child rdf:Seq node.
bool WriteIntArray(const string& prefix, const string& array_name,
const std::vector<int>& values) const override;
bool WriteDoubleArray(const string& prefix, const string& array_name,
const std::vector<double>& values) const override;
// Class-specific methods.
// Constructs a serializer object and writes the xmlNsPtr objects in
// namespaces_ to node_.
static std::unique_ptr<SerializerImpl> FromDataAndSerializeNamespaces(
const std::unordered_map<string, xmlNsPtr>& namespaces, xmlNodePtr node);
// Disallow copying.
SerializerImpl(const SerializerImpl&) = delete;
void operator=(const SerializerImpl&) = delete;
private:
// Writes the xmlNsPtr objects in namespaces_ to node_.
// Modifies namespaces_ by setting each xmlNsPtr's next pointer to the
// subsequent entry in the collection.
bool SerializeNamespaces();
xmlNodePtr node_;
std::unordered_map<string, xmlNsPtr> namespaces_;
};
} // namespace xml
} // namespace xmpmeta
} // namespace dynamic_depth
#endif // DYNAMIC_DEPTH_INTERNAL_XMPMETA_XML_SERIALIZER_IMPL_H_ // NOLINT