exml/tree/namespace.rs
1// Copyright of the original code is the following.
2// --------
3// Summary: interfaces for tree manipulation
4// Description: this module describes the structures found in an tree resulting
5// from an XML or HTML parsing, as well as the API provided for
6// various processing on that tree
7//
8// Copy: See Copyright for the status of this software.
9//
10// Author: Daniel Veillard
11// --------
12// tree.c : implementation of access function for an XML tree.
13//
14// References:
15// XHTML 1.0 W3C REC: http://www.w3.org/TR/2002/REC-xhtml1-20020801/
16//
17// See Copyright for the status of this software.
18//
19// daniel@veillard.com
20
21use std::{
22 any::type_name,
23 borrow::Cow,
24 ops::{Deref, DerefMut},
25 os::raw::c_void,
26 ptr::{NonNull, null_mut},
27};
28
29use super::{
30 InvalidNodePointerCastError, NodeCommon, XML_LOCAL_NAMESPACE, XML_XML_NAMESPACE, XmlDocPtr,
31 XmlElementType, XmlGenericNodePtr, XmlNodePtr, XmlNsType, xml_tree_err_memory,
32};
33
34#[repr(C)]
35pub struct XmlNs {
36 pub next: Option<XmlNsPtr>, /* next Ns link for this node */
37 pub(crate) typ: XmlNsType, /* global or local */
38 pub href: Option<Box<str>>, /* URL for the namespace */
39 pub prefix: Option<Box<str>>, /* prefix for the namespace */
40 pub _private: *mut c_void, /* application data */
41 pub(crate) context: Option<XmlDocPtr>, /* normally an xmlDoc */
42 /// For XPath. Not used except for XPath.
43 /// In the original libxml2, in order to handle namespaces and nodes as a set,
44 /// the `next` is set to the node that will be the set.
45 /// However, this crate provides a separate member for XPath.
46 pub node: Option<XmlGenericNodePtr>,
47}
48
49impl XmlNs {
50 pub fn prefix(&self) -> Option<Cow<'_, str>> {
51 self.prefix.as_deref().map(Cow::Borrowed)
52 }
53
54 pub fn href(&self) -> Option<Cow<'_, str>> {
55 self.href.as_deref().map(Cow::Borrowed)
56 }
57
58 /// Read the value of a node, this can be either the text carried
59 /// directly by this node if it's a TEXT node or the aggregate string
60 /// of the values carried by this node child's (TEXT and ENTITY_REF).
61 ///
62 /// Entity references are substituted.
63 ///
64 /// Returns a new #XmlChar * or null_mut() if no content is available.
65 /// It's up to the caller to free the memory with xml_free().
66 #[doc(alias = "xmlNodeGetContent")]
67 pub fn get_content(&self) -> Option<String> {
68 assert!(matches!(
69 self.element_type(),
70 XmlElementType::XmlNamespaceDecl
71 ));
72 self.href().map(|href| href.into_owned())
73 }
74
75 /// Read the value of a node `cur`, this can be either the text carried
76 /// directly by this node if it's a TEXT node or the aggregate string
77 /// of the values carried by this node child's (TEXT and ENTITY_REF).
78 ///
79 /// Entity references are substituted. Fills up the buffer `buf` with this value.
80 ///
81 /// Returns 0 in case of success and -1 in case of error.
82 #[doc(alias = "xmlBufGetNodeContent")]
83 pub fn get_content_to(&self, buf: &mut String) -> i32 {
84 assert!(matches!(
85 self.element_type(),
86 XmlElementType::XmlNamespaceDecl
87 ));
88 buf.push_str(self.href().unwrap().as_ref());
89
90 0
91 }
92}
93
94impl Default for XmlNs {
95 fn default() -> Self {
96 Self {
97 next: None,
98 typ: XmlNsType::XmlNamespaceDecl,
99 href: None,
100 prefix: None,
101 _private: null_mut(),
102 context: None,
103 node: None,
104 }
105 }
106}
107
108impl NodeCommon for XmlNs {
109 fn document(&self) -> Option<XmlDocPtr> {
110 self.context
111 }
112 fn set_document(&mut self, doc: Option<XmlDocPtr>) {
113 self.context = doc;
114 }
115 fn element_type(&self) -> XmlElementType {
116 self.typ
117 }
118 fn name(&self) -> Option<Cow<'_, str>> {
119 self.href()
120 }
121 fn children(&self) -> Option<XmlGenericNodePtr> {
122 None
123 }
124 fn set_children(&mut self, _children: Option<XmlGenericNodePtr>) {}
125 fn last(&self) -> Option<XmlGenericNodePtr> {
126 None
127 }
128 fn set_last(&mut self, _last: Option<XmlGenericNodePtr>) {}
129 fn next(&self) -> Option<XmlGenericNodePtr> {
130 self.next.map(|ns| ns.into())
131 }
132 fn set_next(&mut self, next: Option<XmlGenericNodePtr>) {
133 self.next = next.map(|p| XmlNsPtr::try_from(p).unwrap());
134 }
135 fn prev(&self) -> Option<XmlGenericNodePtr> {
136 None
137 }
138 fn set_prev(&mut self, _prev: Option<XmlGenericNodePtr>) {}
139 fn parent(&self) -> Option<XmlGenericNodePtr> {
140 None
141 }
142 fn set_parent(&mut self, _parent: Option<XmlGenericNodePtr>) {}
143
144 fn unlink(&mut self) {}
145}
146
147#[derive(PartialEq, Eq, PartialOrd, Ord)]
148pub struct XmlNsPtr(NonNull<XmlNs>);
149
150impl XmlNsPtr {
151 /// Allocate new memory and create new `XmlNsPtr` from an owned xml node.
152 ///
153 /// This method leaks allocated memory.
154 /// Users can use `free` method for deallocating memory.
155 pub(crate) fn new(node: XmlNs) -> Option<Self> {
156 let boxed = Box::new(node);
157 NonNull::new(Box::leak(boxed)).map(Self)
158 }
159
160 /// Create `XmlNsPtr` from a raw pointer.
161 ///
162 /// If `ptr` is a NULL pointer, return `Ok(None)`.
163 /// If `ptr` is a valid pointer of `XmlNs`, return `Ok(Some(Self))`.
164 /// Otherwise, return `Err`.
165 ///
166 /// # Safety
167 /// - `ptr` must be a pointer of types that is implemented `NodeCommon` at least.
168 ///
169 /// # Todo
170 /// - Fix to the private method.
171 pub unsafe fn from_raw(ptr: *mut XmlNs) -> Result<Option<Self>, InvalidNodePointerCastError> {
172 unsafe {
173 if ptr.is_null() {
174 return Ok(None);
175 }
176 match (*ptr).element_type() {
177 XmlElementType::XmlNamespaceDecl => Ok(Some(Self(NonNull::new_unchecked(ptr)))),
178 _ => Err(InvalidNodePointerCastError {
179 from: (*ptr).element_type(),
180 to: type_name::<Self>(),
181 }),
182 }
183 }
184 }
185
186 // pub(crate) fn as_ptr(self) -> *mut XmlNs {
187 // self.0.as_ptr()
188 // }
189
190 /// Deallocate memory.
191 ///
192 /// # Safety
193 /// This method should be called only once.
194 /// If called more than twice, the behavior is undefined.
195 pub(crate) unsafe fn free(self) {
196 unsafe {
197 let _ = *Box::from_raw(self.0.as_ptr());
198 }
199 }
200
201 // /// Acquire the ownership of the inner value.
202 // /// As a result, `self` will be invalid. `self` must not be used after performs this method.
203 // ///
204 // /// # Safety
205 // /// This method should be called only once.
206 // /// If called more than twice, the behavior is undefined.
207 // pub(crate) unsafe fn into_inner(self) -> Box<XmlNs> {
208 // unsafe { Box::from_raw(self.0.as_ptr()) }
209 // }
210}
211
212impl Clone for XmlNsPtr {
213 fn clone(&self) -> Self {
214 *self
215 }
216}
217
218impl Copy for XmlNsPtr {}
219
220impl Deref for XmlNsPtr {
221 type Target = XmlNs;
222 fn deref(&self) -> &Self::Target {
223 // # Safety
224 // I don't implement the pointer casting and addition/subtraction methods
225 // and don't expose the inner `NonNull` for `*mut XmlNs`.
226 // Therefore, as long as the constructor is correctly implemented,
227 // the pointer dereference is valid.
228 unsafe { self.0.as_ref() }
229 }
230}
231
232impl DerefMut for XmlNsPtr {
233 fn deref_mut(&mut self) -> &mut Self::Target {
234 // # Safety
235 // I don't implement the pointer casting and addition/subtraction methods
236 // and don't expose the inner `NonNull` for `*mut XmlNs`.
237 // Therefore, as long as the constructor is correctly implemented,
238 // the pointer dereference is valid.
239 unsafe { self.0.as_mut() }
240 }
241}
242
243impl TryFrom<XmlGenericNodePtr> for XmlNsPtr {
244 type Error = InvalidNodePointerCastError;
245
246 fn try_from(value: XmlGenericNodePtr) -> Result<Self, Self::Error> {
247 match value.element_type() {
248 XmlElementType::XmlNamespaceDecl => Ok(Self(value.0.cast())),
249 _ => Err(InvalidNodePointerCastError {
250 from: value.element_type(),
251 to: type_name::<Self>(),
252 }),
253 }
254 }
255}
256
257impl From<XmlNsPtr> for XmlGenericNodePtr {
258 fn from(value: XmlNsPtr) -> Self {
259 Self(value.0 as NonNull<dyn NodeCommon>)
260 }
261}
262
263impl From<XmlNsPtr> for *mut XmlNs {
264 fn from(value: XmlNsPtr) -> Self {
265 value.0.as_ptr()
266 }
267}
268
269/// Creation of a new Namespace. This function will refuse to create
270/// a namespace with a similar prefix than an existing one present on this node.
271/// Note that for a default namespace, `prefix` should be NULL.
272///
273/// We use href == NULL in the case of an element creation where the namespace was not defined.
274///
275/// Returns a new namespace pointer or NULL
276#[doc(alias = "xmlNewNs")]
277pub fn xml_new_ns(
278 node: Option<XmlNodePtr>,
279 href: Option<&str>,
280 prefix: Option<&str>,
281) -> Option<XmlNsPtr> {
282 if node.is_some_and(|node| node.element_type() != XmlElementType::XmlElementNode) {
283 return None;
284 }
285
286 if prefix == Some("xml") {
287 // xml namespace is predefined, no need to add it
288 if href == Some(XML_XML_NAMESPACE) {
289 return None;
290 }
291
292 // Problem, this is an attempt to bind xml prefix to a wrong
293 // namespace, which breaks
294 // Namespace constraint: Reserved Prefixes and Namespace Names
295 // from XML namespace. But documents authors may not care in
296 // their context so let's proceed.
297 }
298
299 // Allocate a new Namespace and fill the fields.
300 let Some(mut cur) = XmlNsPtr::new(XmlNs {
301 typ: XML_LOCAL_NAMESPACE,
302 ..Default::default()
303 }) else {
304 xml_tree_err_memory("building namespace");
305 return None;
306 };
307
308 cur.href = href.map(|href| href.into());
309 cur.prefix = prefix.map(|prefix| prefix.into());
310
311 // Add it at the end to preserve parsing order ...
312 // and checks for existing use of the prefix
313 if let Some(mut node) = node {
314 if let Some(ns_def) = node.ns_def {
315 let mut prev = ns_def;
316 if prev.prefix == cur.prefix {
317 unsafe {
318 // # Safety
319 // `cur` is created this function and it is not leaked from here.
320 xml_free_ns(cur);
321 }
322 return None;
323 }
324 while let Some(next) = prev.next {
325 prev = next;
326 if prev.prefix == cur.prefix {
327 unsafe {
328 // # Safety
329 // `cur` is created this function and it is not leaked from here.
330 xml_free_ns(cur);
331 }
332 return None;
333 }
334 }
335 prev.next = Some(cur);
336 } else {
337 node.ns_def = Some(cur);
338 }
339 }
340 Some(cur)
341}
342
343/// Free up the structures associated to a namespace
344#[doc(alias = "xmlFreeNs")]
345pub unsafe fn xml_free_ns(cur: XmlNsPtr) {
346 unsafe {
347 cur.free();
348 }
349}
350
351/// Free up all the structures associated to the chained namespaces.
352#[doc(alias = "xmlFreeNsList")]
353pub unsafe fn xml_free_ns_list(cur: XmlNsPtr) {
354 unsafe {
355 let mut next = cur.next;
356 xml_free_ns(cur);
357 while let Some(now) = next {
358 next = now.next;
359 xml_free_ns(now);
360 }
361 }
362}