1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
use writer::formatter::rdf_formatter::*;
use writer::formatter::n_triples_formatter::NTriplesFormatter;
use writer::rdf_writer::RdfWriter;
use graph::Graph;
use node::Node;
use triple::*;
use error::*;
use Result;

/// RDF writer to generate N-Triples syntax.
#[derive(Default)]
pub struct NTriplesWriter {
    formatter: NTriplesFormatter,
}

impl RdfWriter for NTriplesWriter {
    /// Generates the N-Triples syntax for each triple stored in the provided graph.
    ///
    /// Returns an error if invalid N-Triple syntax would be generated.
    ///
    /// # Examples
    ///
    /// ```
    /// use rdf::writer::n_triples_writer::NTriplesWriter;
    /// use rdf::writer::rdf_writer::RdfWriter;
    /// use rdf::graph::Graph;
    ///
    /// let writer = NTriplesWriter::new();
    /// let graph = Graph::new(None);
    ///
    /// assert_eq!(writer.write_to_string(&graph).unwrap(), "".to_string());
    /// ```
    ///
    /// # Failures
    ///
    /// - Invalid triples are to be written to the output that do not conform the NTriples syntax standard.
    ///
    fn write_to_string(&self, graph: &Graph) -> Result<String> {
        let mut output_string = "".to_string();

        for triple in graph.triples_iter() {
            // convert each triple of the graph to N-Triple syntax
            match self.triple_to_n_triples(triple) {
                Ok(str) => {
                    output_string.push_str(&str);
                    output_string.push_str("\n");
                }
                Err(error) => return Err(error),
            }
        }

        Ok(output_string)
    }
}

impl NTriplesWriter {
    /// Constructor of `NTriplesWriter`.
    ///
    /// # Examples
    ///
    /// ```
    /// use rdf::writer::n_triples_writer::NTriplesWriter;
    /// use rdf::writer::rdf_writer::RdfWriter;
    ///
    /// let writer = NTriplesWriter::new();
    /// ```
    pub fn new() -> NTriplesWriter {
        NTriplesWriter {
            formatter: NTriplesFormatter::new(),
        }
    }

    /// Generates the corresponding N-Triples syntax of the provided triple.
    ///
    /// # Examples
    ///
    /// ```
    /// use rdf::writer::n_triples_writer::NTriplesWriter;
    /// use rdf::writer::rdf_writer::RdfWriter;
    /// use rdf::node::Node;
    /// use rdf::triple::Triple;
    /// use rdf::uri::Uri;
    ///
    /// let writer = NTriplesWriter::new();
    ///
    /// let subject = Node::BlankNode { id: "blank".to_string() };
    /// let object = Node::LiteralNode { literal: "literal".to_string(), data_type: None, language: Some("en".to_string()) };
    /// let predicate = Node::UriNode { uri: Uri::new("http://example.org/show/localName".to_string()) };
    /// let triple = Triple::new(&subject, &predicate, &object);
    ///
    /// assert_eq!(writer.triple_to_n_triples(&triple).unwrap(),
    ///            "_:blank <http://example.org/show/localName> \"literal\"@en .".to_string());
    /// ```
    ///
    /// # Failures
    ///
    /// - Invalid node type for a certain position.
    ///
    pub fn triple_to_n_triples(&self, triple: &Triple) -> Result<String> {
        let mut output_string = "".to_string();

        // convert subject
        match self.node_to_n_triples(triple.subject(), &TripleSegment::Subject) {
            Ok(str) => output_string.push_str(&str),
            Err(error) => return Err(error),
        }

        output_string.push_str(" ");

        // convert predicate
        match self.node_to_n_triples(triple.predicate(), &TripleSegment::Predicate) {
            Ok(str) => output_string.push_str(&str),
            Err(error) => return Err(error),
        }

        output_string.push_str(" ");

        // convert object
        match self.node_to_n_triples(triple.object(), &TripleSegment::Object) {
            Ok(str) => output_string.push_str(&str),
            Err(error) => return Err(error),
        }

        output_string.push_str(" .");

        Ok(output_string)
    }

    /// Converts a single node to its corresponding N-Triples representation.
    ///
    /// Checks if the node type is valid considering the triple segment.
    ///
    /// # Examples
    ///
    /// ```
    /// use rdf::writer::n_triples_writer::NTriplesWriter;
    /// use rdf::writer::rdf_writer::RdfWriter;
    /// use rdf::node::Node;
    /// use rdf::triple::TripleSegment;
    ///
    /// let writer = NTriplesWriter::new();
    ///
    /// let node = Node::BlankNode { id: "blank".to_string() };
    ///
    /// assert_eq!(writer.node_to_n_triples(&node, &TripleSegment::Subject).unwrap(),
    ///            "_:blank".to_string());
    /// ```
    ///
    /// # Failures
    ///
    /// - Node type for triple segment does not conform with NTriples syntax standard.
    ///
    pub fn node_to_n_triples(&self, node: &Node, segment: &TripleSegment) -> Result<String> {
        match *node {
      Node::BlankNode { .. } =>
        // blank nodes are not allowed as predicates
        if *segment == TripleSegment::Predicate {
          return Err(Error::new(ErrorType::InvalidWriterOutput,
                                "Blank nodes are not allowed as predicates."))
        },
      Node::LiteralNode { data_type: ref dt, language: ref lang, .. } => {
        // literal nodes are only allowed as objects
        if *segment != TripleSegment::Object {
          return Err(Error::new(ErrorType::InvalidWriterOutput,
                                "Literals are not allowed as subjects or predicates."))
        }

        // either language or data type could be defined, but not both
        if *lang != None && *dt != None {
          return Err(Error::new(ErrorType::InvalidWriterOutput,
                                "Language and data type defined for a literal."))
        }
      },
      _ => {},
    }

        // use the formatter to get the corresponding N-Triple syntax
        Ok(self.formatter.format_node(node))
    }
}