C++程序  |  180行  |  7.34 KB

#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