Home | History | Annotate | Download | only in xml
      1 #include "xmpmeta/xml/serializer_impl.h"
      2 
      3 #include <libxml/tree.h>
      4 
      5 #include "base/integral_types.h"
      6 #include "android-base/logging.h"
      7 #include "strings/numbers.h"
      8 #include "xmpmeta/xml/const.h"
      9 #include "xmpmeta/xml/utils.h"
     10 
     11 namespace dynamic_depth {
     12 namespace xmpmeta {
     13 namespace xml {
     14 
     15 // Methods specific to SerializerImpl.
     16 SerializerImpl::SerializerImpl(
     17     const std::unordered_map<string, xmlNsPtr>& namespaces, xmlNodePtr node)
     18     : node_(node), namespaces_(namespaces) {
     19   CHECK(node_ != nullptr) << "Node cannot be null";
     20   CHECK(node_->name != nullptr) << "Name in the XML node cannot be null";
     21 }
     22 
     23 bool SerializerImpl::SerializeNamespaces() {
     24   if (namespaces_.empty()) {
     25     return true;
     26   }
     27   if (node_->ns == nullptr && !namespaces_.empty()) {
     28     return false;
     29   }
     30   // Check that the namespaces all have hrefs and that there is a value
     31   // for the key node_name.
     32   // Set the namespaces in the root node.
     33   xmlNsPtr node_ns = node_->ns;
     34   for (const auto& entry : namespaces_) {
     35     CHECK(entry.second->href != nullptr) << "Namespace href cannot be null";
     36     if (node_ns != nullptr) {
     37       node_ns->next = entry.second;
     38     }
     39     node_ns = entry.second;
     40   }
     41   return true;
     42 }
     43 
     44 std::unique_ptr<SerializerImpl> SerializerImpl::FromDataAndSerializeNamespaces(
     45     const std::unordered_map<string, xmlNsPtr>& namespaces, xmlNodePtr node) {
     46   std::unique_ptr<SerializerImpl> serializer =
     47       std::unique_ptr<SerializerImpl>(            // NOLINT
     48           new SerializerImpl(namespaces, node));  // NOLINT
     49   if (!serializer->SerializeNamespaces()) {
     50     LOG(ERROR) << "Could not serialize namespaces";
     51     return nullptr;
     52   }
     53   return serializer;
     54 }
     55 
     56 // Implemented methods.
     57 std::unique_ptr<Serializer> SerializerImpl::CreateSerializer(
     58     const string& node_ns_name, const string& node_name) const {
     59   if (node_name.empty()) {
     60     LOG(ERROR) << "Node name is empty";
     61     return nullptr;
     62   }
     63 
     64   if (namespaces_.count(node_ns_name) == 0 && !node_ns_name.empty()) {
     65     LOG(ERROR) << "Prefix " << node_ns_name << " not found in prefix list";
     66     return nullptr;
     67   }
     68 
     69   xmlNodePtr new_node =
     70       xmlNewNode(node_ns_name.empty() ? nullptr : namespaces_.at(node_ns_name),
     71                  ToXmlChar(node_name.data()));
     72   xmlAddChild(node_, new_node);
     73   return std::unique_ptr<Serializer>(
     74       new SerializerImpl(namespaces_, new_node));  // NOLINT
     75 }
     76 
     77 std::unique_ptr<Serializer> SerializerImpl::CreateItemSerializer(
     78     const string& prefix, const string& item_name) const {
     79   if (namespaces_.count(XmlConst::RdfPrefix()) == 0 ||
     80       namespaces_.at(XmlConst::RdfPrefix()) == nullptr) {
     81     LOG(ERROR) << "No RDF prefix namespace found";
     82     return nullptr;
     83   }
     84   if (!prefix.empty() && !namespaces_.count(prefix)) {
     85     LOG(ERROR) << "No namespace found for " << prefix;
     86     return nullptr;
     87   }
     88   if (strcmp(XmlConst::RdfSeq(), FromXmlChar(node_->name)) != 0) {
     89     LOG(ERROR) << "No rdf:Seq node for serializing this item";
     90     return nullptr;
     91   }
     92 
     93   xmlNsPtr rdf_prefix_ns = namespaces_.at(string(XmlConst::RdfPrefix()));
     94   xmlNodePtr li_node = xmlNewNode(nullptr, ToXmlChar(XmlConst::RdfLi()));
     95   xmlNodePtr new_node =
     96       xmlNewNode(prefix.empty() ? nullptr : namespaces_.at(prefix),
     97                  ToXmlChar(item_name.data()));
     98   xmlSetNs(li_node, rdf_prefix_ns);
     99   xmlAddChild(node_, li_node);
    100   xmlAddChild(li_node, new_node);
    101   return std::unique_ptr<Serializer>(
    102       new SerializerImpl(namespaces_, new_node));  // NOLINT
    103 }
    104 
    105 std::unique_ptr<Serializer> SerializerImpl::CreateListSerializer(
    106     const string& prefix, const string& list_name) const {
    107   if (namespaces_.count(XmlConst::RdfPrefix()) == 0 ||
    108       namespaces_.at(XmlConst::RdfPrefix()) == nullptr) {
    109     LOG(ERROR) << "No RDF prefix namespace found";
    110     return nullptr;
    111   }
    112   if (!prefix.empty() && !namespaces_.count(prefix)) {
    113     LOG(ERROR) << "No namespace found for " << prefix;
    114     return nullptr;
    115   }
    116 
    117   xmlNodePtr list_node =
    118       xmlNewNode(prefix.empty() ? nullptr : namespaces_.at(prefix),
    119                  ToXmlChar(list_name.data()));
    120   xmlNsPtr rdf_prefix_ns = namespaces_.at(string(XmlConst::RdfPrefix()));
    121   xmlNodePtr seq_node = xmlNewNode(nullptr, ToXmlChar(XmlConst::RdfSeq()));
    122   xmlSetNs(seq_node, rdf_prefix_ns);
    123   xmlAddChild(list_node, seq_node);
    124   xmlAddChild(node_, list_node);
    125   return std::unique_ptr<Serializer>(
    126       new SerializerImpl(namespaces_, seq_node));  // NOLINT
    127 }
    128 
    129 bool SerializerImpl::WriteBoolProperty(const string& prefix, const string& name,
    130                                        bool value) const {
    131   const string& bool_str = (value ? "true" : "false");
    132   return WriteProperty(prefix, name, bool_str);
    133 }
    134 
    135 bool SerializerImpl::WriteProperty(const string& prefix, const string& name,
    136                                    const string& value) const {
    137   if (!strcmp(XmlConst::RdfSeq(), FromXmlChar(node_->name))) {
    138     LOG(ERROR) << "Cannot write a property on an rdf:Seq node";
    139     return false;
    140   }
    141   if (name.empty()) {
    142     LOG(ERROR) << "Property name is empty";
    143     return false;
    144   }
    145 
    146   // Check that prefix has a corresponding namespace href.
    147   if (!prefix.empty() && namespaces_.count(prefix) == 0) {
    148     LOG(ERROR) << "No namespace found for prefix " << prefix;
    149     return false;
    150   }
    151 
    152   // Serialize the property in the format Prefix:Name="Value".
    153   xmlSetNsProp(node_, prefix.empty() ? nullptr : namespaces_.at(prefix),
    154                ToXmlChar(name.data()), ToXmlChar(value.data()));
    155   return true;
    156 }
    157 
    158 bool SerializerImpl::WriteIntArray(const string& prefix,
    159                                    const string& array_name,
    160                                    const std::vector<int>& values) const {
    161   if (!strcmp(XmlConst::RdfSeq(), FromXmlChar(node_->name))) {
    162     LOG(ERROR) << "Cannot write a property on an rdf:Seq node";
    163     return false;
    164   }
    165   if (values.empty()) {
    166     LOG(WARNING) << "No values to write";
    167     return false;
    168   }
    169   if (namespaces_.count(XmlConst::RdfPrefix()) == 0 ||
    170       namespaces_.at(XmlConst::RdfPrefix()) == nullptr) {
    171     LOG(ERROR) << "No RDF prefix found";
    172     return false;
    173   }
    174   if (!prefix.empty() && !namespaces_.count(prefix)) {
    175     LOG(ERROR) << "No namespace found for " << prefix;
    176     return false;
    177   }
    178   if (array_name.empty()) {
    179     LOG(ERROR) << "Parent name cannot be empty";
    180     return false;
    181   }
    182 
    183   xmlNodePtr array_parent_node =
    184       xmlNewNode(prefix.empty() ? nullptr : namespaces_.at(prefix),
    185                  ToXmlChar(array_name.data()));
    186   xmlAddChild(node_, array_parent_node);
    187 
    188   xmlNsPtr rdf_prefix_ns = namespaces_.at(XmlConst::RdfPrefix());
    189   xmlNodePtr seq_node = xmlNewNode(nullptr, ToXmlChar(XmlConst::RdfSeq()));
    190   xmlSetNs(seq_node, rdf_prefix_ns);
    191   xmlAddChild(array_parent_node, seq_node);
    192   for (int value : values) {
    193     xmlNodePtr li_node = xmlNewNode(nullptr, ToXmlChar(XmlConst::RdfLi()));
    194     xmlSetNs(li_node, rdf_prefix_ns);
    195     xmlAddChild(seq_node, li_node);
    196     xmlNodeSetContent(li_node, ToXmlChar(std::to_string(value).c_str()));
    197   }
    198 
    199   return true;
    200 }
    201 
    202 bool SerializerImpl::WriteDoubleArray(const string& prefix,
    203                                       const string& array_name,
    204                                       const std::vector<double>& values) const {
    205   if (!strcmp(XmlConst::RdfSeq(), FromXmlChar(node_->name))) {
    206     LOG(ERROR) << "Cannot write a property on an rdf:Seq node";
    207     return false;
    208   }
    209   if (values.empty()) {
    210     LOG(WARNING) << "No values to write";
    211     return false;
    212   }
    213   if (namespaces_.count(XmlConst::RdfPrefix()) == 0 ||
    214       namespaces_.at(XmlConst::RdfPrefix()) == nullptr) {
    215     LOG(ERROR) << "No RDF prefix found";
    216     return false;
    217   }
    218   if (!prefix.empty() && !namespaces_.count(prefix)) {
    219     LOG(ERROR) << "No namespace found for " << prefix;
    220     return false;
    221   }
    222   if (array_name.empty()) {
    223     LOG(ERROR) << "Parent name cannot be empty";
    224     return false;
    225   }
    226 
    227   xmlNodePtr array_parent_node =
    228       xmlNewNode(prefix.empty() ? nullptr : namespaces_.at(prefix),
    229                  ToXmlChar(array_name.data()));
    230   xmlAddChild(node_, array_parent_node);
    231 
    232   xmlNsPtr rdf_prefix_ns = namespaces_.at(XmlConst::RdfPrefix());
    233   xmlNodePtr seq_node = xmlNewNode(nullptr, ToXmlChar(XmlConst::RdfSeq()));
    234   xmlSetNs(seq_node, rdf_prefix_ns);
    235   xmlAddChild(array_parent_node, seq_node);
    236   for (float value : values) {
    237     xmlNodePtr li_node = xmlNewNode(nullptr, ToXmlChar(XmlConst::RdfLi()));
    238     xmlSetNs(li_node, rdf_prefix_ns);
    239     xmlAddChild(seq_node, li_node);
    240     xmlNodeSetContent(
    241         li_node, ToXmlChar(dynamic_depth::strings::SimpleFtoa(value).c_str()));
    242   }
    243 
    244   return true;
    245 }
    246 
    247 }  // namespace xml
    248 }  // namespace xmpmeta
    249 }  // namespace dynamic_depth
    250