xot/creation.rs
1use crate::error::Error;
2use crate::id::NameId;
3use crate::xmlvalue::{Attribute, Comment, Element, Namespace, ProcessingInstruction, Text, Value};
4use crate::xotdata::{Node, Xot};
5use crate::{NamespaceId, PrefixId};
6
7/// ## Creation
8///
9/// These are functions to help create nodes.
10///
11/// See also the convenience manipulation methods like [`Xot::append_element`]
12/// in the manipulation section.
13impl Xot {
14 pub(crate) fn new_node(&mut self, value: Value) -> Node {
15 Node::new(self.arena.new_node(value))
16 }
17
18 /// Create a new, unattached document node without document element.
19 ///
20 /// You can use this to create a new document from scratch.
21 /// If you don't attach at a single element later, the document
22 /// is going to be invalid.
23 ///
24 /// ```rust
25 /// use xot::Xot;
26 ///
27 /// let mut xot = Xot::new();
28 /// let doc_name = xot.add_name("doc");
29 /// let doc_el = xot.new_element(doc_name);
30 /// let txt = xot.new_text("Hello, world!");
31 /// xot.append(doc_el, txt)?;
32 ///
33 /// /// now create the document
34 /// let document = xot.new_document();
35 /// xot.append(document, doc_el)?;
36 ///
37 /// assert_eq!(xot.to_string(document)?, "<doc>Hello, world!</doc>");
38 /// # Ok::<(), xot::Error>(())
39 /// ```
40 pub fn new_document(&mut self) -> Node {
41 let root = Value::Document;
42 self.new_node(root)
43 }
44
45 /// Create a new document node with a document element.
46 ///
47 /// You can use this to create a new document from scratch. You have to
48 /// supply a document element. If you want to create an empty document node,
49 /// use `Xot::new_document`.
50 ///
51 /// ```rust
52 /// use xot::Xot;
53 ///
54 /// let mut xot = Xot::new();
55 /// let doc_name = xot.add_name("doc");
56 /// let doc_el = xot.new_element(doc_name);
57 /// let txt = xot.new_text("Hello, world!");
58 /// xot.append(doc_el, txt)?;
59 ///
60 /// /// now create the document
61 /// let document = xot.new_document_with_element(doc_el)?;
62 ///
63 /// assert_eq!(xot.to_string(document)?, "<doc>Hello, world!</doc>");
64 /// # Ok::<(), xot::Error>(())
65 /// ```
66 pub fn new_document_with_element(&mut self, node: Node) -> Result<Node, Error> {
67 if !self.is_element(node) {
68 return Err(Error::InvalidOperation(
69 "You must supply an element node".to_string(),
70 ));
71 }
72 let document_node = self.new_document();
73 self.append(document_node, node)?;
74 Ok(document_node)
75 }
76
77 /// Create a new, unattached element node given element name.
78 ///
79 /// You supply a [`crate::NameId`] or a [`crate::xmlname`] structure that
80 /// can be turned into a name id.
81 ///
82 /// To create a potentially new name you can use [`Xot::add_name`] or
83 /// [`Xot::add_name_ns`]. If the name already exists the existing name id
84 /// is returned.
85 ///
86 /// To reuse an existing name that has been previously used, you can use
87 /// [`Xot::name`] or [`Xot::name_ns`].
88 ///
89 /// ```rust
90 /// use xot::Xot;
91 ///
92 /// let mut xot = Xot::new();
93 /// let doc_name = xot.add_name("doc");
94 /// let doc_el = xot.new_element(doc_name);
95 ///
96 /// let root = xot.new_document_with_element(doc_el)?;
97 /// assert_eq!(xot.to_string(root)?, "<doc/>");
98 /// # Ok::<(), xot::Error>(())
99 /// ```
100 ///
101 /// With a namespaced element:
102 ///
103 /// ```rust
104 /// use xot::Xot;
105 ///
106 /// let mut xot = Xot::new();
107 /// let ns = xot.add_namespace("http://example.com");
108 /// let ex = xot.add_prefix("ex");
109 ///
110 /// // create name in namespace
111 /// let doc_name = xot.add_name_ns("doc", ns);
112 /// let doc_el = xot.new_element(doc_name);
113 ///
114 /// // set up namepace prefix for element so it serializes to XML nicely
115 /// xot.namespaces_mut(doc_el).insert(ex, ns);
116 ///
117 /// let root = xot.new_document_with_element(doc_el)?;
118 ///
119 /// assert_eq!(xot.to_string(root)?, r#"<ex:doc xmlns:ex="http://example.com"/>"#);
120 /// # Ok::<(), xot::Error>(())
121 /// ```
122 ///
123 /// Or with `xmlname`:
124 ///
125 ///```
126 /// use xot::{Xot, xmlname};
127 ///
128 /// let mut xot = Xot::new();
129 ///
130 /// let namespace = xmlname::CreateNamespace::new(&mut xot, "ex", "http://example.com");
131 /// let doc_name = xmlname::CreateName::namespaced(&mut xot, "doc", &namespace);
132 ///
133 /// let doc_el = xot.new_element(doc_name);
134 ///
135 /// // set up namepace prefix for element so it serializes to XML nicely
136 /// xot.append_namespace(doc_el, &namespace);
137 ///
138 /// let root = xot.new_document_with_element(doc_el)?;
139 ///
140 /// assert_eq!(xot.to_string(root)?, r#"<ex:doc xmlns:ex="http://example.com"/>"#);
141 ///
142 /// # Ok::<(), xot::Error>(())
143 /// ```
144 pub fn new_element(&mut self, name: impl Into<NameId>) -> Node {
145 let element = Value::Element(Element::new(name.into()));
146 self.new_node(element)
147 }
148
149 /// Create a new, unattached text node.
150 ///
151 /// ```rust
152 /// use xot::Xot;
153 ///
154 /// let mut xot = Xot::new();
155 /// let root = xot.parse(r#"<doc/>"#)?;
156 /// let doc_el = xot.document_element(root)?;
157 /// let txt = xot.new_text("Hello, world!");
158 /// xot.append(doc_el, txt)?;
159 /// assert_eq!(xot.to_string(root)?, "<doc>Hello, world!</doc>");
160 /// # Ok::<(), xot::Error>(())
161 /// ```
162 pub fn new_text(&mut self, text: &str) -> Node {
163 let text = Value::Text(Text::new(text.to_string()));
164 self.new_node(text)
165 }
166
167 /// Create a new, unattached comment node given comment text.
168 ///
169 /// ```rust
170 /// use xot::Xot;
171 ///
172 /// let mut xot = Xot::new();
173 /// let root = xot.parse(r#"<doc/>"#)?;
174 /// let doc_el = xot.document_element(root)?;
175 /// let comment = xot.new_comment("Hello, world!");
176 /// xot.append(doc_el, comment)?;
177 /// assert_eq!(xot.to_string(root)?, "<doc><!--Hello, world!--></doc>");
178 /// # Ok::<(), xot::Error>(())
179 /// ```
180 pub fn new_comment(&mut self, comment: &str) -> Node {
181 let comment = Value::Comment(Comment::new(comment.to_string()));
182 self.new_node(comment)
183 }
184
185 /// Create a new, unattached processing instruction.
186 ///
187 /// ```rust
188 /// use xot::Xot;
189 ///
190 /// let mut xot = Xot::new();
191 /// let target = xot.add_name("target");
192 /// let root = xot.parse(r#"<doc/>"#)?;
193 /// let doc_el = xot.document_element(root)?;
194 /// let pi = xot.new_processing_instruction(target, Some("data"));
195 /// xot.append(doc_el, pi)?;
196 /// assert_eq!(xot.to_string(root)?, r#"<doc><?target data?></doc>"#);
197 /// # Ok::<(), xot::Error>(())
198 /// ```
199 pub fn new_processing_instruction(
200 &mut self,
201 target: impl Into<NameId>,
202 data: Option<&str>,
203 ) -> Node {
204 let pi = Value::ProcessingInstruction(ProcessingInstruction::new(
205 target.into(),
206 data.map(|s| s.to_string()),
207 ));
208 self.new_node(pi)
209 }
210
211 /// Create a new, unattached attribute node.
212 ///
213 /// You can then use [`Xot::append_attribute_node`] to add it to an element node.
214 ///
215 /// This method is useful in situations where attributes need to be created
216 /// independently of elements, but for many use cases you can use the
217 /// [`Xot::attributes_mut`] API to create attributes instead.
218 ///
219 /// ```rust
220 /// use xot::Xot;
221 ///
222 /// let mut xot = Xot::new();
223 /// let foo = xot.add_name("foo");
224 /// let root = xot.parse(r#"<doc/>"#)?;
225 /// let doc_el = xot.document_element(root)?;
226 /// let attr = xot.new_attribute_node(foo, "FOO".to_string());
227 /// xot.append_attribute_node(doc_el, attr)?;
228 /// assert_eq!(xot.to_string(root)?, r#"<doc foo="FOO"/>"#);
229 /// # Ok::<(), xot::Error>(())
230 /// ```
231 pub fn new_attribute_node(&mut self, name: impl Into<NameId>, value: String) -> Node {
232 let attr = Value::Attribute(Attribute {
233 name_id: name.into(),
234 value,
235 });
236 self.new_node(attr)
237 }
238
239 /// Create a new, unattached namespace declaration node.
240 ///
241 /// You can then use [`Xot::append_namespace_node`] to add it to an element
242 /// node.
243 ///
244 /// This method is useful in situations where namespaces need to be created
245 /// independently of elements, but for many use cases you can use the
246 /// [`Xot::namespaces_mut`] API to create namespaces instead.
247 ///
248 /// ```rust
249 /// use xot::Xot;
250 ///
251 /// let mut xot = Xot::new();
252 /// let foo = xot.add_prefix("foo");
253 /// let ns = xot.add_namespace("http://example.com");
254 /// let root = xot.parse(r#"<doc/>"#)?;
255 /// let doc_el = xot.document_element(root)?;
256 /// let ns = xot.new_namespace_node(foo, ns);
257 /// xot.append_namespace_node(doc_el, ns)?;
258 /// assert_eq!(xot.to_string(root)?, r#"<doc xmlns:foo="http://example.com"/>"#);
259 ///
260 /// # Ok::<(), xot::Error>(())
261 /// ```
262 pub fn new_namespace_node(&mut self, prefix: PrefixId, namespace: NamespaceId) -> Node {
263 let ns = Value::Namespace(Namespace {
264 prefix_id: prefix,
265 namespace_id: namespace,
266 });
267 self.new_node(ns)
268 }
269}