/src/quick-xml/src/events/mod.rs
Line | Count | Source |
1 | | //! Defines zero-copy XML events used throughout this library. |
2 | | //! |
3 | | //! A XML event often represents part of a XML element. |
4 | | //! They occur both during reading and writing and are |
5 | | //! usually used with the stream-oriented API. |
6 | | //! |
7 | | //! For example, the XML element |
8 | | //! ```xml |
9 | | //! <name attr="value">Inner text</name> |
10 | | //! ``` |
11 | | //! consists of the three events `Start`, `Text` and `End`. |
12 | | //! They can also represent other parts in an XML document like the |
13 | | //! XML declaration. Each Event usually contains further information, |
14 | | //! like the tag name, the attribute or the inner text. |
15 | | //! |
16 | | //! See [`Event`] for a list of all possible events. |
17 | | //! |
18 | | //! # Reading |
19 | | //! When reading a XML stream, the events are emitted by [`Reader::read_event`] |
20 | | //! and [`Reader::read_event_into`]. You must listen |
21 | | //! for the different types of events you are interested in. |
22 | | //! |
23 | | //! See [`Reader`] for further information. |
24 | | //! |
25 | | //! # Writing |
26 | | //! When writing the XML document, you must create the XML element |
27 | | //! by constructing the events it consists of and pass them to the writer |
28 | | //! sequentially. |
29 | | //! |
30 | | //! See [`Writer`] for further information. |
31 | | //! |
32 | | //! [`Reader::read_event`]: crate::reader::Reader::read_event |
33 | | //! [`Reader::read_event_into`]: crate::reader::Reader::read_event_into |
34 | | //! [`Reader`]: crate::reader::Reader |
35 | | //! [`Writer`]: crate::writer::Writer |
36 | | //! [`Event`]: crate::events::Event |
37 | | |
38 | | pub mod attributes; |
39 | | |
40 | | #[cfg(feature = "encoding")] |
41 | | use encoding_rs::Encoding; |
42 | | use std::borrow::Cow; |
43 | | use std::fmt::{self, Debug, Formatter}; |
44 | | use std::iter::FusedIterator; |
45 | | use std::mem::replace; |
46 | | use std::ops::Deref; |
47 | | use std::str::from_utf8; |
48 | | |
49 | | use crate::encoding::{Decoder, EncodingError}; |
50 | | use crate::errors::{Error, IllFormedError}; |
51 | | use crate::escape::{ |
52 | | escape, minimal_escape, normalize_xml10_eols, normalize_xml11_eols, parse_number, |
53 | | partial_escape, EscapeError, |
54 | | }; |
55 | | use crate::name::{LocalName, QName}; |
56 | | use crate::utils::{name_len, trim_xml_end, trim_xml_start, write_cow_string, Bytes}; |
57 | | use attributes::{AttrError, Attribute, Attributes}; |
58 | | |
59 | | /// Opening tag data (`Event::Start`), with optional attributes: `<name attr="value">`. |
60 | | /// |
61 | | /// The name can be accessed using the [`name`] or [`local_name`] methods. |
62 | | /// An iterator over the attributes is returned by the [`attributes`] method. |
63 | | /// |
64 | | /// This event implements `Deref<Target = [u8]>`. The `deref()` implementation |
65 | | /// returns the content of this event between `<` and `>` or `/>`: |
66 | | /// |
67 | | /// ``` |
68 | | /// # use quick_xml::events::{BytesStart, Event}; |
69 | | /// # use quick_xml::reader::Reader; |
70 | | /// # use pretty_assertions::assert_eq; |
71 | | /// // Remember, that \ at the end of string literal strips |
72 | | /// // all space characters to the first non-space character |
73 | | /// let mut reader = Reader::from_str("\ |
74 | | /// <element a1 = 'val1' a2=\"val2\" />\ |
75 | | /// <element a1 = 'val1' a2=\"val2\" >" |
76 | | /// ); |
77 | | /// let content = "element a1 = 'val1' a2=\"val2\" "; |
78 | | /// let event = BytesStart::from_content(content, 7); |
79 | | /// |
80 | | /// assert_eq!(reader.read_event().unwrap(), Event::Empty(event.borrow())); |
81 | | /// assert_eq!(reader.read_event().unwrap(), Event::Start(event.borrow())); |
82 | | /// // deref coercion of &BytesStart to &[u8] |
83 | | /// assert_eq!(&event as &[u8], content.as_bytes()); |
84 | | /// // AsRef<[u8]> for &T + deref coercion |
85 | | /// assert_eq!(event.as_ref(), content.as_bytes()); |
86 | | /// ``` |
87 | | /// |
88 | | /// [`name`]: Self::name |
89 | | /// [`local_name`]: Self::local_name |
90 | | /// [`attributes`]: Self::attributes |
91 | | #[derive(Clone, Eq, PartialEq)] |
92 | | pub struct BytesStart<'a> { |
93 | | /// content of the element, before any utf8 conversion |
94 | | pub(crate) buf: Cow<'a, [u8]>, |
95 | | /// end of the element name, the name starts at that the start of `buf` |
96 | | pub(crate) name_len: usize, |
97 | | /// Encoding used for `buf` |
98 | | decoder: Decoder, |
99 | | } |
100 | | |
101 | | impl<'a> BytesStart<'a> { |
102 | | /// Internal constructor, used by `Reader`. Supplies data in reader's encoding |
103 | | #[inline] |
104 | 8.49M | pub(crate) const fn wrap(content: &'a [u8], name_len: usize, decoder: Decoder) -> Self { |
105 | 8.49M | BytesStart { |
106 | 8.49M | buf: Cow::Borrowed(content), |
107 | 8.49M | name_len, |
108 | 8.49M | decoder, |
109 | 8.49M | } |
110 | 8.49M | } |
111 | | |
112 | | /// Creates a new `BytesStart` from the given name. |
113 | | /// |
114 | | /// # Warning |
115 | | /// |
116 | | /// `name` must be a valid name. |
117 | | #[inline] |
118 | 17.0k | pub fn new<C: Into<Cow<'a, str>>>(name: C) -> Self { |
119 | 17.0k | let buf = str_cow_to_bytes(name); |
120 | 17.0k | BytesStart { |
121 | 17.0k | name_len: buf.len(), |
122 | 17.0k | buf, |
123 | 17.0k | decoder: Decoder::utf8(), |
124 | 17.0k | } |
125 | 17.0k | } <quick_xml::events::BytesStart>::new::<&alloc::string::String> Line | Count | Source | 118 | 13.4k | pub fn new<C: Into<Cow<'a, str>>>(name: C) -> Self { | 119 | 13.4k | let buf = str_cow_to_bytes(name); | 120 | 13.4k | BytesStart { | 121 | 13.4k | name_len: buf.len(), | 122 | 13.4k | buf, | 123 | 13.4k | decoder: Decoder::utf8(), | 124 | 13.4k | } | 125 | 13.4k | } |
<quick_xml::events::BytesStart>::new::<&str> Line | Count | Source | 118 | 3.53k | pub fn new<C: Into<Cow<'a, str>>>(name: C) -> Self { | 119 | 3.53k | let buf = str_cow_to_bytes(name); | 120 | 3.53k | BytesStart { | 121 | 3.53k | name_len: buf.len(), | 122 | 3.53k | buf, | 123 | 3.53k | decoder: Decoder::utf8(), | 124 | 3.53k | } | 125 | 3.53k | } |
|
126 | | |
127 | | /// Creates a new `BytesStart` from the given content (name + attributes). |
128 | | /// |
129 | | /// # Warning |
130 | | /// |
131 | | /// `&content[..name_len]` must be a valid name, and the remainder of `content` |
132 | | /// must be correctly-formed attributes. Neither are checked, it is possible |
133 | | /// to generate invalid XML if `content` or `name_len` are incorrect. |
134 | | #[inline] |
135 | 5.38k | pub fn from_content<C: Into<Cow<'a, str>>>(content: C, name_len: usize) -> Self { |
136 | 5.38k | BytesStart { |
137 | 5.38k | buf: str_cow_to_bytes(content), |
138 | 5.38k | name_len, |
139 | 5.38k | decoder: Decoder::utf8(), |
140 | 5.38k | } |
141 | 5.38k | } |
142 | | |
143 | | /// Converts the event into an owned event. |
144 | 0 | pub fn into_owned(self) -> BytesStart<'static> { |
145 | 0 | BytesStart { |
146 | 0 | buf: Cow::Owned(self.buf.into_owned()), |
147 | 0 | name_len: self.name_len, |
148 | 0 | decoder: self.decoder, |
149 | 0 | } |
150 | 0 | } |
151 | | |
152 | | /// Converts the event into an owned event without taking ownership of Event |
153 | 0 | pub fn to_owned(&self) -> BytesStart<'static> { |
154 | 0 | BytesStart { |
155 | 0 | buf: Cow::Owned(self.buf.clone().into_owned()), |
156 | 0 | name_len: self.name_len, |
157 | 0 | decoder: self.decoder, |
158 | 0 | } |
159 | 0 | } |
160 | | |
161 | | /// Converts the event into a borrowed event. Most useful when paired with [`to_end`]. |
162 | | /// |
163 | | /// # Example |
164 | | /// |
165 | | /// ``` |
166 | | /// use quick_xml::events::{BytesStart, Event}; |
167 | | /// # use quick_xml::writer::Writer; |
168 | | /// # use quick_xml::Error; |
169 | | /// |
170 | | /// struct SomeStruct<'a> { |
171 | | /// attrs: BytesStart<'a>, |
172 | | /// // ... |
173 | | /// } |
174 | | /// # impl<'a> SomeStruct<'a> { |
175 | | /// # fn example(&self) -> Result<(), Error> { |
176 | | /// # let mut writer = Writer::new(Vec::new()); |
177 | | /// |
178 | | /// writer.write_event(Event::Start(self.attrs.borrow()))?; |
179 | | /// // ... |
180 | | /// writer.write_event(Event::End(self.attrs.to_end()))?; |
181 | | /// # Ok(()) |
182 | | /// # }} |
183 | | /// ``` |
184 | | /// |
185 | | /// [`to_end`]: Self::to_end |
186 | 11.4M | pub fn borrow(&self) -> BytesStart<'_> { |
187 | 11.4M | BytesStart { |
188 | 11.4M | buf: Cow::Borrowed(&self.buf), |
189 | 11.4M | name_len: self.name_len, |
190 | 11.4M | decoder: self.decoder, |
191 | 11.4M | } |
192 | 11.4M | } |
193 | | |
194 | | /// Creates new paired close tag |
195 | | #[inline] |
196 | 10.4k | pub fn to_end(&self) -> BytesEnd<'_> { |
197 | 10.4k | BytesEnd::from(self.name()) |
198 | 10.4k | } |
199 | | |
200 | | /// Get the decoder, used to decode bytes, read by the reader which produces |
201 | | /// this event, to the strings. |
202 | | /// |
203 | | /// When event was created manually, encoding is UTF-8. |
204 | | /// |
205 | | /// If [`encoding`] feature is enabled and no encoding is specified in declaration, |
206 | | /// defaults to UTF-8. |
207 | | /// |
208 | | /// [`encoding`]: ../index.html#encoding |
209 | | #[inline] |
210 | | pub const fn decoder(&self) -> Decoder { |
211 | | self.decoder |
212 | | } |
213 | | |
214 | | /// Gets the undecoded raw tag name, as present in the input stream. |
215 | | #[inline] |
216 | 14.1M | pub fn name(&self) -> QName<'_> { |
217 | 14.1M | QName(&self.buf[..self.name_len]) |
218 | 14.1M | } <quick_xml::events::BytesStart>::name Line | Count | Source | 216 | 10.4k | pub fn name(&self) -> QName<'_> { | 217 | 10.4k | QName(&self.buf[..self.name_len]) | 218 | 10.4k | } |
<quick_xml::events::BytesStart>::name Line | Count | Source | 216 | 8.45M | pub fn name(&self) -> QName<'_> { | 217 | 8.45M | QName(&self.buf[..self.name_len]) | 218 | 8.45M | } |
<quick_xml::events::BytesStart>::name Line | Count | Source | 216 | 5.67M | pub fn name(&self) -> QName<'_> { | 217 | 5.67M | QName(&self.buf[..self.name_len]) | 218 | 5.67M | } |
|
219 | | |
220 | | /// Gets the undecoded raw local tag name (excluding namespace) as present |
221 | | /// in the input stream. |
222 | | /// |
223 | | /// All content up to and including the first `:` character is removed from the tag name. |
224 | | #[inline] |
225 | | pub fn local_name(&self) -> LocalName<'_> { |
226 | | self.name().into() |
227 | | } |
228 | | |
229 | | /// Edit the name of the BytesStart in-place |
230 | | /// |
231 | | /// # Warning |
232 | | /// |
233 | | /// `name` must be a valid name. |
234 | 0 | pub fn set_name(&mut self, name: &[u8]) -> &mut BytesStart<'a> { |
235 | 0 | let bytes = self.buf.to_mut(); |
236 | 0 | bytes.splice(..self.name_len, name.iter().cloned()); |
237 | 0 | self.name_len = name.len(); |
238 | 0 | self |
239 | 0 | } |
240 | | } |
241 | | |
242 | | /// Attribute-related methods |
243 | | impl<'a> BytesStart<'a> { |
244 | | /// Consumes `self` and yield a new `BytesStart` with additional attributes from an iterator. |
245 | | /// |
246 | | /// The yielded items must be convertible to [`Attribute`] using `Into`. |
247 | | pub fn with_attributes<'b, I>(mut self, attributes: I) -> Self |
248 | | where |
249 | | I: IntoIterator, |
250 | | I::Item: Into<Attribute<'b>>, |
251 | | { |
252 | | self.extend_attributes(attributes); |
253 | | self |
254 | | } |
255 | | |
256 | | /// Add additional attributes to this tag using an iterator. |
257 | | /// |
258 | | /// The yielded items must be convertible to [`Attribute`] using `Into`. |
259 | 12.0k | pub fn extend_attributes<'b, I>(&mut self, attributes: I) -> &mut BytesStart<'a> |
260 | 12.0k | where |
261 | 12.0k | I: IntoIterator, |
262 | 12.0k | I::Item: Into<Attribute<'b>>, |
263 | | { |
264 | 895k | for attr in attributes { |
265 | 883k | self.push_attribute(attr); |
266 | 883k | } |
267 | 12.0k | self |
268 | 12.0k | } <quick_xml::events::BytesStart>::extend_attributes::<core::iter::adapters::copied::Copied<core::slice::iter::Iter<(&str, &str)>>> Line | Count | Source | 259 | 8.56k | pub fn extend_attributes<'b, I>(&mut self, attributes: I) -> &mut BytesStart<'a> | 260 | 8.56k | where | 261 | 8.56k | I: IntoIterator, | 262 | 8.56k | I::Item: Into<Attribute<'b>>, | 263 | | { | 264 | 719k | for attr in attributes { | 265 | 710k | self.push_attribute(attr); | 266 | 710k | } | 267 | 8.56k | self | 268 | 8.56k | } |
<quick_xml::events::BytesStart>::extend_attributes::<alloc::vec::into_iter::IntoIter<(&str, &str)>> Line | Count | Source | 259 | 3.53k | pub fn extend_attributes<'b, I>(&mut self, attributes: I) -> &mut BytesStart<'a> | 260 | 3.53k | where | 261 | 3.53k | I: IntoIterator, | 262 | 3.53k | I::Item: Into<Attribute<'b>>, | 263 | | { | 264 | 176k | for attr in attributes { | 265 | 172k | self.push_attribute(attr); | 266 | 172k | } | 267 | 3.53k | self | 268 | 3.53k | } |
|
269 | | |
270 | | /// Adds an attribute to this element. |
271 | 891k | pub fn push_attribute<'b, A>(&mut self, attr: A) |
272 | 891k | where |
273 | 891k | A: Into<Attribute<'b>>, |
274 | | { |
275 | 891k | self.buf.to_mut().push(b' '); |
276 | 891k | self.push_attr(attr.into()); |
277 | 891k | } <quick_xml::events::BytesStart>::push_attribute::<quick_xml::events::attributes::Attribute> Line | Count | Source | 271 | 8.56k | pub fn push_attribute<'b, A>(&mut self, attr: A) | 272 | 8.56k | where | 273 | 8.56k | A: Into<Attribute<'b>>, | 274 | | { | 275 | 8.56k | self.buf.to_mut().push(b' '); | 276 | 8.56k | self.push_attr(attr.into()); | 277 | 8.56k | } |
<quick_xml::events::BytesStart>::push_attribute::<(&str, &str)> Line | Count | Source | 271 | 883k | pub fn push_attribute<'b, A>(&mut self, attr: A) | 272 | 883k | where | 273 | 883k | A: Into<Attribute<'b>>, | 274 | | { | 275 | 883k | self.buf.to_mut().push(b' '); | 276 | 883k | self.push_attr(attr.into()); | 277 | 883k | } |
|
278 | | |
279 | | /// Remove all attributes from the ByteStart |
280 | 0 | pub fn clear_attributes(&mut self) -> &mut BytesStart<'a> { |
281 | 0 | self.buf.to_mut().truncate(self.name_len); |
282 | 0 | self |
283 | 0 | } |
284 | | |
285 | | /// Returns an iterator over the attributes of this tag. |
286 | 7.07M | pub fn attributes(&self) -> Attributes<'_> { |
287 | 7.07M | Attributes::wrap(&self.buf, self.name_len, false, self.decoder) |
288 | 7.07M | } |
289 | | |
290 | | /// Returns an iterator over the HTML-like attributes of this tag (no mandatory quotes or `=`). |
291 | 0 | pub fn html_attributes(&self) -> Attributes<'_> { |
292 | 0 | Attributes::wrap(&self.buf, self.name_len, true, self.decoder) |
293 | 0 | } |
294 | | |
295 | | /// Gets the undecoded raw string with the attributes of this tag as a `&[u8]`, |
296 | | /// including the whitespace after the tag name if there is any. |
297 | | #[inline] |
298 | | pub fn attributes_raw(&self) -> &[u8] { |
299 | | &self.buf[self.name_len..] |
300 | | } |
301 | | |
302 | | /// Try to get an attribute |
303 | 29.1k | pub fn try_get_attribute<N: AsRef<[u8]> + Sized>( |
304 | 29.1k | &'a self, |
305 | 29.1k | attr_name: N, |
306 | 29.1k | ) -> Result<Option<Attribute<'a>>, AttrError> { |
307 | 29.1k | for a in self.attributes().with_checks(false) { |
308 | 25.5k | let a = a?; |
309 | 17.6k | if a.key.as_ref() == attr_name.as_ref() { |
310 | 1.31k | return Ok(Some(a)); |
311 | 16.2k | } |
312 | | } |
313 | 19.9k | Ok(None) |
314 | 29.1k | } |
315 | | |
316 | | /// Adds an attribute to this element. |
317 | 891k | pub(crate) fn push_attr<'b>(&mut self, attr: Attribute<'b>) { |
318 | 891k | let bytes = self.buf.to_mut(); |
319 | 891k | bytes.extend_from_slice(attr.key.as_ref()); |
320 | 891k | bytes.extend_from_slice(b"=\""); |
321 | | // FIXME: need to escape attribute content |
322 | 891k | bytes.extend_from_slice(attr.value.as_ref()); |
323 | 891k | bytes.push(b'"'); |
324 | 891k | } |
325 | | |
326 | | /// Adds new line in existing element |
327 | 0 | pub(crate) fn push_newline(&mut self) { |
328 | 0 | self.buf.to_mut().push(b'\n'); |
329 | 0 | } |
330 | | |
331 | | /// Adds indentation bytes in existing element |
332 | 0 | pub(crate) fn push_indent(&mut self, indent: &[u8]) { |
333 | 0 | self.buf.to_mut().extend_from_slice(indent); |
334 | 0 | } |
335 | | } |
336 | | |
337 | | impl<'a> Debug for BytesStart<'a> { |
338 | 11.3M | fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
339 | 11.3M | write!(f, "BytesStart {{ buf: ")?; |
340 | 11.3M | write_cow_string(f, &self.buf)?; |
341 | 11.3M | write!(f, ", name_len: {} }}", self.name_len) |
342 | 11.3M | } |
343 | | } |
344 | | |
345 | | impl<'a> Deref for BytesStart<'a> { |
346 | | type Target = [u8]; |
347 | | |
348 | 5.72M | fn deref(&self) -> &[u8] { |
349 | 5.72M | &self.buf |
350 | 5.72M | } |
351 | | } |
352 | | |
353 | | #[cfg(feature = "arbitrary")] |
354 | | impl<'a> arbitrary::Arbitrary<'a> for BytesStart<'a> { |
355 | 3.63k | fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> { |
356 | 3.63k | let s = <&str>::arbitrary(u)?; |
357 | 3.63k | if s.is_empty() || !s.chars().all(char::is_alphanumeric) { |
358 | 103 | return Err(arbitrary::Error::IncorrectFormat); |
359 | 3.53k | } |
360 | 3.53k | let mut result = Self::new(s); |
361 | 3.53k | result.extend_attributes(Vec::<(&str, &str)>::arbitrary(u)?.into_iter()); |
362 | 3.53k | Ok(result) |
363 | 3.63k | } |
364 | | |
365 | 0 | fn size_hint(depth: usize) -> (usize, Option<usize>) { |
366 | 0 | return <&str as arbitrary::Arbitrary>::size_hint(depth); |
367 | 0 | } |
368 | | } |
369 | | |
370 | | //////////////////////////////////////////////////////////////////////////////////////////////////// |
371 | | |
372 | | /// Closing tag data (`Event::End`): `</name>`. |
373 | | /// |
374 | | /// The name can be accessed using the [`name`] or [`local_name`] methods. |
375 | | /// |
376 | | /// This event implements `Deref<Target = [u8]>`. The `deref()` implementation |
377 | | /// returns the content of this event between `</` and `>`. |
378 | | /// |
379 | | /// Note, that inner text will not contain `>` character inside: |
380 | | /// |
381 | | /// ``` |
382 | | /// # use quick_xml::events::{BytesEnd, Event}; |
383 | | /// # use quick_xml::reader::Reader; |
384 | | /// # use pretty_assertions::assert_eq; |
385 | | /// let mut reader = Reader::from_str(r#"<element></element a1 = 'val1' a2="val2" >"#); |
386 | | /// // Note, that this entire string considered as a .name() |
387 | | /// let content = "element a1 = 'val1' a2=\"val2\" "; |
388 | | /// let event = BytesEnd::new(content); |
389 | | /// |
390 | | /// reader.config_mut().trim_markup_names_in_closing_tags = false; |
391 | | /// reader.config_mut().check_end_names = false; |
392 | | /// reader.read_event().unwrap(); // Skip `<element>` |
393 | | /// |
394 | | /// assert_eq!(reader.read_event().unwrap(), Event::End(event.borrow())); |
395 | | /// assert_eq!(event.name().as_ref(), content.as_bytes()); |
396 | | /// // deref coercion of &BytesEnd to &[u8] |
397 | | /// assert_eq!(&event as &[u8], content.as_bytes()); |
398 | | /// // AsRef<[u8]> for &T + deref coercion |
399 | | /// assert_eq!(event.as_ref(), content.as_bytes()); |
400 | | /// ``` |
401 | | /// |
402 | | /// [`name`]: Self::name |
403 | | /// [`local_name`]: Self::local_name |
404 | | #[derive(Clone, Eq, PartialEq)] |
405 | | pub struct BytesEnd<'a> { |
406 | | name: Cow<'a, [u8]>, |
407 | | } |
408 | | |
409 | | impl<'a> BytesEnd<'a> { |
410 | | /// Internal constructor, used by `Reader`. Supplies data in reader's encoding |
411 | | #[inline] |
412 | 1.15M | pub(crate) const fn wrap(name: Cow<'a, [u8]>) -> Self { |
413 | 1.15M | BytesEnd { name } |
414 | 1.15M | } <quick_xml::events::BytesEnd>::wrap Line | Count | Source | 412 | 10.4k | pub(crate) const fn wrap(name: Cow<'a, [u8]>) -> Self { | 413 | 10.4k | BytesEnd { name } | 414 | 10.4k | } |
<quick_xml::events::BytesEnd>::wrap Line | Count | Source | 412 | 68.4k | pub(crate) const fn wrap(name: Cow<'a, [u8]>) -> Self { | 413 | 68.4k | BytesEnd { name } | 414 | 68.4k | } |
<quick_xml::events::BytesEnd>::wrap Line | Count | Source | 412 | 1.07M | pub(crate) const fn wrap(name: Cow<'a, [u8]>) -> Self { | 413 | 1.07M | BytesEnd { name } | 414 | 1.07M | } |
|
415 | | |
416 | | /// Creates a new `BytesEnd` borrowing a slice. |
417 | | /// |
418 | | /// # Warning |
419 | | /// |
420 | | /// `name` must be a valid name. |
421 | | #[inline] |
422 | 1.68k | pub fn new<C: Into<Cow<'a, str>>>(name: C) -> Self { |
423 | 1.68k | Self::wrap(str_cow_to_bytes(name)) |
424 | 1.68k | } |
425 | | |
426 | | /// Converts the event into an owned event. |
427 | 0 | pub fn into_owned(self) -> BytesEnd<'static> { |
428 | 0 | BytesEnd { |
429 | 0 | name: Cow::Owned(self.name.into_owned()), |
430 | 0 | } |
431 | 0 | } |
432 | | |
433 | | /// Converts the event into a borrowed event. |
434 | | #[inline] |
435 | 2.24M | pub fn borrow(&self) -> BytesEnd<'_> { |
436 | 2.24M | BytesEnd { |
437 | 2.24M | name: Cow::Borrowed(&self.name), |
438 | 2.24M | } |
439 | 2.24M | } <quick_xml::events::BytesEnd>::borrow Line | Count | Source | 435 | 1.68k | pub fn borrow(&self) -> BytesEnd<'_> { | 436 | 1.68k | BytesEnd { | 437 | 1.68k | name: Cow::Borrowed(&self.name), | 438 | 1.68k | } | 439 | 1.68k | } |
<quick_xml::events::BytesEnd>::borrow Line | Count | Source | 435 | 2.24M | pub fn borrow(&self) -> BytesEnd<'_> { | 436 | 2.24M | BytesEnd { | 437 | 2.24M | name: Cow::Borrowed(&self.name), | 438 | 2.24M | } | 439 | 2.24M | } |
|
440 | | |
441 | | /// Gets the undecoded raw tag name, as present in the input stream. |
442 | | #[inline] |
443 | 2.24M | pub fn name(&self) -> QName<'_> { |
444 | 2.24M | QName(&self.name) |
445 | 2.24M | } Unexecuted instantiation: <quick_xml::events::BytesEnd>::name <quick_xml::events::BytesEnd>::name Line | Count | Source | 443 | 2.24M | pub fn name(&self) -> QName<'_> { | 444 | 2.24M | QName(&self.name) | 445 | 2.24M | } |
|
446 | | |
447 | | /// Gets the undecoded raw local tag name (excluding namespace) as present |
448 | | /// in the input stream. |
449 | | /// |
450 | | /// All content up to and including the first `:` character is removed from the tag name. |
451 | | #[inline] |
452 | 1.12M | pub fn local_name(&self) -> LocalName<'_> { |
453 | 1.12M | self.name().into() |
454 | 1.12M | } |
455 | | } |
456 | | |
457 | | impl<'a> Debug for BytesEnd<'a> { |
458 | 2.24M | fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
459 | 2.24M | write!(f, "BytesEnd {{ name: ")?; |
460 | 2.24M | write_cow_string(f, &self.name)?; |
461 | 2.24M | write!(f, " }}") |
462 | 2.24M | } |
463 | | } |
464 | | |
465 | | impl<'a> Deref for BytesEnd<'a> { |
466 | | type Target = [u8]; |
467 | | |
468 | 1.13M | fn deref(&self) -> &[u8] { |
469 | 1.13M | &self.name |
470 | 1.13M | } |
471 | | } |
472 | | |
473 | | impl<'a> From<QName<'a>> for BytesEnd<'a> { |
474 | | #[inline] |
475 | 10.4k | fn from(name: QName<'a>) -> Self { |
476 | 10.4k | Self::wrap(name.into_inner().into()) |
477 | 10.4k | } |
478 | | } |
479 | | |
480 | | #[cfg(feature = "arbitrary")] |
481 | | impl<'a> arbitrary::Arbitrary<'a> for BytesEnd<'a> { |
482 | 1.68k | fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> { |
483 | 1.68k | Ok(Self::new(<&str>::arbitrary(u)?)) |
484 | 1.68k | } |
485 | 0 | fn size_hint(depth: usize) -> (usize, Option<usize>) { |
486 | 0 | return <&str as arbitrary::Arbitrary>::size_hint(depth); |
487 | 0 | } |
488 | | } |
489 | | |
490 | | //////////////////////////////////////////////////////////////////////////////////////////////////// |
491 | | |
492 | | /// Data from various events (most notably, `Event::Text`) that stored in XML |
493 | | /// in escaped form. Internally data is stored in escaped form. |
494 | | /// |
495 | | /// This event implements `Deref<Target = [u8]>`. The `deref()` implementation |
496 | | /// returns the content of this event. In case of comment this is everything |
497 | | /// between `<!--` and `-->` and the text of comment will not contain `-->` inside. |
498 | | /// In case of DTD this is everything between `<!DOCTYPE` + spaces and closing `>` |
499 | | /// (i.e. in case of DTD the first character is never space): |
500 | | /// |
501 | | /// ``` |
502 | | /// # use quick_xml::events::{BytesText, Event}; |
503 | | /// # use quick_xml::reader::Reader; |
504 | | /// # use pretty_assertions::assert_eq; |
505 | | /// // Remember, that \ at the end of string literal strips |
506 | | /// // all space characters to the first non-space character |
507 | | /// let mut reader = Reader::from_str("\ |
508 | | /// <!DOCTYPE comment or text >\ |
509 | | /// comment or text \ |
510 | | /// <!--comment or text -->" |
511 | | /// ); |
512 | | /// let content = "comment or text "; |
513 | | /// let event = BytesText::new(content); |
514 | | /// |
515 | | /// assert_eq!(reader.read_event().unwrap(), Event::DocType(event.borrow())); |
516 | | /// assert_eq!(reader.read_event().unwrap(), Event::Text(event.borrow())); |
517 | | /// assert_eq!(reader.read_event().unwrap(), Event::Comment(event.borrow())); |
518 | | /// // deref coercion of &BytesText to &[u8] |
519 | | /// assert_eq!(&event as &[u8], content.as_bytes()); |
520 | | /// // AsRef<[u8]> for &T + deref coercion |
521 | | /// assert_eq!(event.as_ref(), content.as_bytes()); |
522 | | /// ``` |
523 | | #[derive(Clone, Eq, PartialEq)] |
524 | | pub struct BytesText<'a> { |
525 | | /// Escaped then encoded content of the event. Content is encoded in the XML |
526 | | /// document encoding when event comes from the reader and should be in the |
527 | | /// document encoding when event passed to the writer |
528 | | content: Cow<'a, [u8]>, |
529 | | /// Encoding in which the `content` is stored inside the event |
530 | | decoder: Decoder, |
531 | | } |
532 | | |
533 | | impl<'a> BytesText<'a> { |
534 | | /// Creates a new `BytesText` from an escaped byte sequence in the specified encoding. |
535 | | #[inline] |
536 | 799k | pub(crate) fn wrap<C: Into<Cow<'a, [u8]>>>(content: C, decoder: Decoder) -> Self { |
537 | 799k | Self { |
538 | 799k | content: content.into(), |
539 | 799k | decoder, |
540 | 799k | } |
541 | 799k | } <quick_xml::events::BytesText>::wrap::<alloc::borrow::Cow<[u8]>> Line | Count | Source | 536 | 69.9k | pub(crate) fn wrap<C: Into<Cow<'a, [u8]>>>(content: C, decoder: Decoder) -> Self { | 537 | 69.9k | Self { | 538 | 69.9k | content: content.into(), | 539 | 69.9k | decoder, | 540 | 69.9k | } | 541 | 69.9k | } |
<quick_xml::events::BytesText>::wrap::<&[u8]> Line | Count | Source | 536 | 729k | pub(crate) fn wrap<C: Into<Cow<'a, [u8]>>>(content: C, decoder: Decoder) -> Self { | 537 | 729k | Self { | 538 | 729k | content: content.into(), | 539 | 729k | decoder, | 540 | 729k | } | 541 | 729k | } |
|
542 | | |
543 | | /// Creates a new `BytesText` from an escaped string. |
544 | | #[inline] |
545 | 7.12k | pub fn from_escaped<C: Into<Cow<'a, str>>>(content: C) -> Self { |
546 | 7.12k | Self::wrap(str_cow_to_bytes(content), Decoder::utf8()) |
547 | 7.12k | } <quick_xml::events::BytesText>::from_escaped::<&str> Line | Count | Source | 545 | 2.71k | pub fn from_escaped<C: Into<Cow<'a, str>>>(content: C) -> Self { | 546 | 2.71k | Self::wrap(str_cow_to_bytes(content), Decoder::utf8()) | 547 | 2.71k | } |
<quick_xml::events::BytesText>::from_escaped::<alloc::borrow::Cow<str>> Line | Count | Source | 545 | 4.41k | pub fn from_escaped<C: Into<Cow<'a, str>>>(content: C) -> Self { | 546 | 4.41k | Self::wrap(str_cow_to_bytes(content), Decoder::utf8()) | 547 | 4.41k | } |
|
548 | | |
549 | | /// Creates a new `BytesText` from a string. The string is expected not to |
550 | | /// be escaped. |
551 | | #[inline] |
552 | 4.41k | pub fn new(content: &'a str) -> Self { |
553 | 4.41k | Self::from_escaped(escape(content)) |
554 | 4.41k | } |
555 | | |
556 | | /// Ensures that all data is owned to extend the object's lifetime if |
557 | | /// necessary. |
558 | | #[inline] |
559 | 0 | pub fn into_owned(self) -> BytesText<'static> { |
560 | 0 | BytesText { |
561 | 0 | content: self.content.into_owned().into(), |
562 | 0 | decoder: self.decoder, |
563 | 0 | } |
564 | 0 | } |
565 | | |
566 | | /// Extracts the inner `Cow` from the `BytesText` event container. |
567 | | #[inline] |
568 | | pub fn into_inner(self) -> Cow<'a, [u8]> { |
569 | | self.content |
570 | | } |
571 | | |
572 | | /// Converts the event into a borrowed event. |
573 | | #[inline] |
574 | 451k | pub fn borrow(&self) -> BytesText<'_> { |
575 | 451k | BytesText { |
576 | 451k | content: Cow::Borrowed(&self.content), |
577 | 451k | decoder: self.decoder, |
578 | 451k | } |
579 | 451k | } <quick_xml::events::BytesText>::borrow Line | Count | Source | 574 | 4.40k | pub fn borrow(&self) -> BytesText<'_> { | 575 | 4.40k | BytesText { | 576 | 4.40k | content: Cow::Borrowed(&self.content), | 577 | 4.40k | decoder: self.decoder, | 578 | 4.40k | } | 579 | 4.40k | } |
<quick_xml::events::BytesText>::borrow Line | Count | Source | 574 | 446k | pub fn borrow(&self) -> BytesText<'_> { | 575 | 446k | BytesText { | 576 | 446k | content: Cow::Borrowed(&self.content), | 577 | 446k | decoder: self.decoder, | 578 | 446k | } | 579 | 446k | } |
|
580 | | |
581 | | /// Decodes the content of the event. |
582 | | /// |
583 | | /// This will allocate if the value contains any escape sequences or in |
584 | | /// non-UTF-8 encoding. |
585 | | /// |
586 | | /// This method does not normalizes end-of-line characters as required by [specification]. |
587 | | /// Usually you need [`xml_content()`](Self::xml_content) instead of this method. |
588 | | /// |
589 | | /// [specification]: https://www.w3.org/TR/xml11/#sec-line-ends |
590 | 223k | pub fn decode(&self) -> Result<Cow<'a, str>, EncodingError> { |
591 | 223k | self.decoder.decode_cow(&self.content) |
592 | 223k | } |
593 | | |
594 | | /// Decodes the content of the XML 1.0 or HTML event. |
595 | | /// |
596 | | /// When this event produced by the reader, it uses the encoding information |
597 | | /// associated with that reader to interpret the raw bytes contained within |
598 | | /// this text event. |
599 | | /// |
600 | | /// This will allocate if the value contains any escape sequences or in non-UTF-8 |
601 | | /// encoding, or EOL normalization is required. |
602 | | /// |
603 | | /// Note, that this method should be used only if event represents XML 1.0 or HTML content, |
604 | | /// because rules for normalizing EOLs for [XML 1.0] / [HTML] and [XML 1.1] differs. |
605 | | /// |
606 | | /// This method also can be used to get HTML content, because rules the same. |
607 | | /// |
608 | | /// [XML 1.0]: https://www.w3.org/TR/xml/#sec-line-ends |
609 | | /// [XML 1.1]: https://www.w3.org/TR/xml11/#sec-line-ends |
610 | | /// [HTML]: https://html.spec.whatwg.org/#normalize-newlines |
611 | 0 | pub fn xml10_content(&self) -> Result<Cow<'a, str>, EncodingError> { |
612 | 0 | self.decoder.content(&self.content, normalize_xml10_eols) |
613 | 0 | } |
614 | | |
615 | | /// Decodes the content of the XML 1.1 event. |
616 | | /// |
617 | | /// When this event produced by the reader, it uses the encoding information |
618 | | /// associated with that reader to interpret the raw bytes contained within |
619 | | /// this text event. |
620 | | /// |
621 | | /// This will allocate if the value contains any escape sequences or in non-UTF-8 |
622 | | /// encoding, or EOL normalization is required. |
623 | | /// |
624 | | /// Note, that this method should be used only if event represents XML 1.1 content, |
625 | | /// because rules for normalizing EOLs for [XML 1.0], [XML 1.1] and [HTML] differs. |
626 | | /// |
627 | | /// To get HTML content use [`xml10_content()`](Self::xml10_content). |
628 | | /// |
629 | | /// [XML 1.0]: https://www.w3.org/TR/xml/#sec-line-ends |
630 | | /// [XML 1.1]: https://www.w3.org/TR/xml11/#sec-line-ends |
631 | | /// [HTML]: https://html.spec.whatwg.org/#normalize-newlines |
632 | 0 | pub fn xml11_content(&self) -> Result<Cow<'a, str>, EncodingError> { |
633 | 0 | self.decoder.content(&self.content, normalize_xml11_eols) |
634 | 0 | } |
635 | | |
636 | | /// Alias for [`xml11_content()`](Self::xml11_content). |
637 | | #[inline] |
638 | | pub fn xml_content(&self) -> Result<Cow<'a, str>, EncodingError> { |
639 | | self.xml11_content() |
640 | | } |
641 | | |
642 | | /// Alias for [`xml10_content()`](Self::xml10_content). |
643 | | #[inline] |
644 | | pub fn html_content(&self) -> Result<Cow<'a, str>, EncodingError> { |
645 | | self.xml10_content() |
646 | | } |
647 | | |
648 | | /// Removes leading XML whitespace bytes from text content. |
649 | | /// |
650 | | /// Returns `true` if content is empty after that |
651 | 0 | pub fn inplace_trim_start(&mut self) -> bool { |
652 | 0 | self.content = trim_cow( |
653 | 0 | replace(&mut self.content, Cow::Borrowed(b"")), |
654 | | trim_xml_start, |
655 | | ); |
656 | 0 | self.content.is_empty() |
657 | 0 | } |
658 | | |
659 | | /// Removes trailing XML whitespace bytes from text content. |
660 | | /// |
661 | | /// Returns `true` if content is empty after that |
662 | 0 | pub fn inplace_trim_end(&mut self) -> bool { |
663 | 0 | self.content = trim_cow(replace(&mut self.content, Cow::Borrowed(b"")), trim_xml_end); |
664 | 0 | self.content.is_empty() |
665 | 0 | } |
666 | | } |
667 | | |
668 | | impl<'a> Debug for BytesText<'a> { |
669 | 446k | fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
670 | 446k | write!(f, "BytesText {{ content: ")?; |
671 | 446k | write_cow_string(f, &self.content)?; |
672 | 446k | write!(f, " }}") |
673 | 446k | } |
674 | | } |
675 | | |
676 | | impl<'a> Deref for BytesText<'a> { |
677 | | type Target = [u8]; |
678 | | |
679 | 249k | fn deref(&self) -> &[u8] { |
680 | 249k | &self.content |
681 | 249k | } |
682 | | } |
683 | | |
684 | | #[cfg(feature = "arbitrary")] |
685 | | impl<'a> arbitrary::Arbitrary<'a> for BytesText<'a> { |
686 | 4.43k | fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> { |
687 | 4.43k | let s = <&str>::arbitrary(u)?; |
688 | 4.43k | if !s.chars().all(char::is_alphanumeric) { |
689 | 25 | return Err(arbitrary::Error::IncorrectFormat); |
690 | 4.41k | } |
691 | 4.41k | Ok(Self::new(s)) |
692 | 4.43k | } |
693 | | |
694 | 0 | fn size_hint(depth: usize) -> (usize, Option<usize>) { |
695 | 0 | return <&str as arbitrary::Arbitrary>::size_hint(depth); |
696 | 0 | } |
697 | | } |
698 | | |
699 | | //////////////////////////////////////////////////////////////////////////////////////////////////// |
700 | | |
701 | | /// CDATA content contains unescaped data from the reader. If you want to write them as a text, |
702 | | /// [convert](Self::escape) it to [`BytesText`]. |
703 | | /// |
704 | | /// This event implements `Deref<Target = [u8]>`. The `deref()` implementation |
705 | | /// returns the content of this event between `<![CDATA[` and `]]>`. |
706 | | /// |
707 | | /// Note, that inner text will not contain `]]>` sequence inside: |
708 | | /// |
709 | | /// ``` |
710 | | /// # use quick_xml::events::{BytesCData, Event}; |
711 | | /// # use quick_xml::reader::Reader; |
712 | | /// # use pretty_assertions::assert_eq; |
713 | | /// let mut reader = Reader::from_str("<![CDATA[ CDATA section ]]>"); |
714 | | /// let content = " CDATA section "; |
715 | | /// let event = BytesCData::new(content); |
716 | | /// |
717 | | /// assert_eq!(reader.read_event().unwrap(), Event::CData(event.borrow())); |
718 | | /// // deref coercion of &BytesCData to &[u8] |
719 | | /// assert_eq!(&event as &[u8], content.as_bytes()); |
720 | | /// // AsRef<[u8]> for &T + deref coercion |
721 | | /// assert_eq!(event.as_ref(), content.as_bytes()); |
722 | | /// ``` |
723 | | #[derive(Clone, Eq, PartialEq)] |
724 | | pub struct BytesCData<'a> { |
725 | | content: Cow<'a, [u8]>, |
726 | | /// Encoding in which the `content` is stored inside the event |
727 | | decoder: Decoder, |
728 | | } |
729 | | |
730 | | impl<'a> BytesCData<'a> { |
731 | | /// Creates a new `BytesCData` from a byte sequence in the specified encoding. |
732 | | #[inline] |
733 | 78.5k | pub(crate) fn wrap<C: Into<Cow<'a, [u8]>>>(content: C, decoder: Decoder) -> Self { |
734 | 78.5k | Self { |
735 | 78.5k | content: content.into(), |
736 | 78.5k | decoder, |
737 | 78.5k | } |
738 | 78.5k | } <quick_xml::events::BytesCData>::wrap::<alloc::borrow::Cow<[u8]>> Line | Count | Source | 733 | 7.59k | pub(crate) fn wrap<C: Into<Cow<'a, [u8]>>>(content: C, decoder: Decoder) -> Self { | 734 | 7.59k | Self { | 735 | 7.59k | content: content.into(), | 736 | 7.59k | decoder, | 737 | 7.59k | } | 738 | 7.59k | } |
<quick_xml::events::BytesCData>::wrap::<&[u8]> Line | Count | Source | 733 | 70.9k | pub(crate) fn wrap<C: Into<Cow<'a, [u8]>>>(content: C, decoder: Decoder) -> Self { | 734 | 70.9k | Self { | 735 | 70.9k | content: content.into(), | 736 | 70.9k | decoder, | 737 | 70.9k | } | 738 | 70.9k | } |
|
739 | | |
740 | | /// Creates a new `BytesCData` from a string. |
741 | | /// |
742 | | /// # Warning |
743 | | /// |
744 | | /// `content` must not contain the `]]>` sequence. You can use |
745 | | /// [`BytesCData::escaped`] to escape the content instead. |
746 | | #[inline] |
747 | 7.59k | pub fn new<C: Into<Cow<'a, str>>>(content: C) -> Self { |
748 | 7.59k | Self::wrap(str_cow_to_bytes(content), Decoder::utf8()) |
749 | 7.59k | } |
750 | | |
751 | | /// Creates an iterator of `BytesCData` from a string. |
752 | | /// |
753 | | /// If a string contains `]]>`, it needs to be split into multiple `CDATA` |
754 | | /// sections, splitting the `]]` and `>` characters, because the CDATA closing |
755 | | /// sequence cannot be escaped. This iterator yields a `BytesCData` instance |
756 | | /// for each of those sections. |
757 | | /// |
758 | | /// # Examples |
759 | | /// |
760 | | /// ``` |
761 | | /// # use quick_xml::events::BytesCData; |
762 | | /// # use pretty_assertions::assert_eq; |
763 | | /// let content = ""; |
764 | | /// let cdata = BytesCData::escaped(content).collect::<Vec<_>>(); |
765 | | /// assert_eq!(cdata, &[BytesCData::new("")]); |
766 | | /// |
767 | | /// let content = "Certain tokens like ]]> can be difficult and <invalid>"; |
768 | | /// let cdata = BytesCData::escaped(content).collect::<Vec<_>>(); |
769 | | /// assert_eq!(cdata, &[ |
770 | | /// BytesCData::new("Certain tokens like ]]"), |
771 | | /// BytesCData::new("> can be difficult and <invalid>"), |
772 | | /// ]); |
773 | | /// |
774 | | /// let content = "foo]]>bar]]>baz]]>quux"; |
775 | | /// let cdata = BytesCData::escaped(content).collect::<Vec<_>>(); |
776 | | /// assert_eq!(cdata, &[ |
777 | | /// BytesCData::new("foo]]"), |
778 | | /// BytesCData::new(">bar]]"), |
779 | | /// BytesCData::new(">baz]]"), |
780 | | /// BytesCData::new(">quux"), |
781 | | /// ]); |
782 | | /// ``` |
783 | | #[inline] |
784 | | pub fn escaped(content: &'a str) -> CDataIterator<'a> { |
785 | | CDataIterator { |
786 | | unprocessed: content.as_bytes(), |
787 | | finished: false, |
788 | | } |
789 | | } |
790 | | |
791 | | /// Ensures that all data is owned to extend the object's lifetime if |
792 | | /// necessary. |
793 | | #[inline] |
794 | 0 | pub fn into_owned(self) -> BytesCData<'static> { |
795 | 0 | BytesCData { |
796 | 0 | content: self.content.into_owned().into(), |
797 | 0 | decoder: self.decoder, |
798 | 0 | } |
799 | 0 | } |
800 | | |
801 | | /// Extracts the inner `Cow` from the `BytesCData` event container. |
802 | | #[inline] |
803 | | pub fn into_inner(self) -> Cow<'a, [u8]> { |
804 | | self.content |
805 | | } |
806 | | |
807 | | /// Converts the event into a borrowed event. |
808 | | #[inline] |
809 | 128k | pub fn borrow(&self) -> BytesCData<'_> { |
810 | 128k | BytesCData { |
811 | 128k | content: Cow::Borrowed(&self.content), |
812 | 128k | decoder: self.decoder, |
813 | 128k | } |
814 | 128k | } <quick_xml::events::BytesCData>::borrow Line | Count | Source | 809 | 2.77k | pub fn borrow(&self) -> BytesCData<'_> { | 810 | 2.77k | BytesCData { | 811 | 2.77k | content: Cow::Borrowed(&self.content), | 812 | 2.77k | decoder: self.decoder, | 813 | 2.77k | } | 814 | 2.77k | } |
<quick_xml::events::BytesCData>::borrow Line | Count | Source | 809 | 125k | pub fn borrow(&self) -> BytesCData<'_> { | 810 | 125k | BytesCData { | 811 | 125k | content: Cow::Borrowed(&self.content), | 812 | 125k | decoder: self.decoder, | 813 | 125k | } | 814 | 125k | } |
|
815 | | |
816 | | /// Converts this CDATA content to an escaped version, that can be written |
817 | | /// as an usual text in XML. |
818 | | /// |
819 | | /// This function performs following replacements: |
820 | | /// |
821 | | /// | Character | Replacement |
822 | | /// |-----------|------------ |
823 | | /// | `<` | `<` |
824 | | /// | `>` | `>` |
825 | | /// | `&` | `&` |
826 | | /// | `'` | `'` |
827 | | /// | `"` | `"` |
828 | 62.8k | pub fn escape(self) -> Result<BytesText<'a>, EncodingError> { |
829 | 62.8k | let decoded = self.decode()?; |
830 | 62.8k | Ok(BytesText::wrap( |
831 | 62.8k | match escape(decoded) { |
832 | 45.4k | Cow::Borrowed(escaped) => Cow::Borrowed(escaped.as_bytes()), |
833 | 17.3k | Cow::Owned(escaped) => Cow::Owned(escaped.into_bytes()), |
834 | | }, |
835 | 62.8k | Decoder::utf8(), |
836 | | )) |
837 | 62.8k | } |
838 | | |
839 | | /// Converts this CDATA content to an escaped version, that can be written |
840 | | /// as an usual text in XML. |
841 | | /// |
842 | | /// In XML text content, it is allowed (though not recommended) to leave |
843 | | /// the quote special characters `"` and `'` unescaped. |
844 | | /// |
845 | | /// This function performs following replacements: |
846 | | /// |
847 | | /// | Character | Replacement |
848 | | /// |-----------|------------ |
849 | | /// | `<` | `<` |
850 | | /// | `>` | `>` |
851 | | /// | `&` | `&` |
852 | 0 | pub fn partial_escape(self) -> Result<BytesText<'a>, EncodingError> { |
853 | 0 | let decoded = self.decode()?; |
854 | 0 | Ok(BytesText::wrap( |
855 | 0 | match partial_escape(decoded) { |
856 | 0 | Cow::Borrowed(escaped) => Cow::Borrowed(escaped.as_bytes()), |
857 | 0 | Cow::Owned(escaped) => Cow::Owned(escaped.into_bytes()), |
858 | | }, |
859 | 0 | Decoder::utf8(), |
860 | | )) |
861 | 0 | } |
862 | | |
863 | | /// Converts this CDATA content to an escaped version, that can be written |
864 | | /// as an usual text in XML. This method escapes only those characters that |
865 | | /// must be escaped according to the [specification]. |
866 | | /// |
867 | | /// This function performs following replacements: |
868 | | /// |
869 | | /// | Character | Replacement |
870 | | /// |-----------|------------ |
871 | | /// | `<` | `<` |
872 | | /// | `&` | `&` |
873 | | /// |
874 | | /// [specification]: https://www.w3.org/TR/xml11/#syntax |
875 | 0 | pub fn minimal_escape(self) -> Result<BytesText<'a>, EncodingError> { |
876 | 0 | let decoded = self.decode()?; |
877 | 0 | Ok(BytesText::wrap( |
878 | 0 | match minimal_escape(decoded) { |
879 | 0 | Cow::Borrowed(escaped) => Cow::Borrowed(escaped.as_bytes()), |
880 | 0 | Cow::Owned(escaped) => Cow::Owned(escaped.into_bytes()), |
881 | | }, |
882 | 0 | Decoder::utf8(), |
883 | | )) |
884 | 0 | } |
885 | | |
886 | | /// Decodes the raw input byte content of the CDATA section into a string, |
887 | | /// without performing XML entity escaping. |
888 | | /// |
889 | | /// When this event produced by the XML reader, it uses the encoding information |
890 | | /// associated with that reader to interpret the raw bytes contained within this |
891 | | /// CDATA event. |
892 | | /// |
893 | | /// This method does not normalizes end-of-line characters as required by [specification]. |
894 | | /// Usually you need [`xml_content()`](Self::xml_content) instead of this method. |
895 | | /// |
896 | | /// [specification]: https://www.w3.org/TR/xml11/#sec-line-ends |
897 | 62.8k | pub fn decode(&self) -> Result<Cow<'a, str>, EncodingError> { |
898 | 62.8k | self.decoder.decode_cow(&self.content) |
899 | 62.8k | } |
900 | | |
901 | | /// Decodes the raw input byte content of the CDATA section of the XML 1.0 or |
902 | | /// HTML event into a string. |
903 | | /// |
904 | | /// When this event produced by the reader, it uses the encoding information |
905 | | /// associated with that reader to interpret the raw bytes contained within |
906 | | /// this CDATA event. |
907 | | /// |
908 | | /// This will allocate if the value in non-UTF-8 encoding, or EOL normalization |
909 | | /// is required. |
910 | | /// |
911 | | /// Note, that this method should be used only if event represents XML 1.0 or HTML content, |
912 | | /// because rules for normalizing EOLs for [XML 1.0] / [HTML] and [XML 1.1] differs. |
913 | | /// |
914 | | /// This method also can be used to get HTML content, because rules the same. |
915 | | /// |
916 | | /// [XML 1.0]: https://www.w3.org/TR/xml/#sec-line-ends |
917 | | /// [XML 1.1]: https://www.w3.org/TR/xml11/#sec-line-ends |
918 | | /// [HTML]: https://html.spec.whatwg.org/#normalize-newlines |
919 | 0 | pub fn xml10_content(&self) -> Result<Cow<'a, str>, EncodingError> { |
920 | 0 | self.decoder.content(&self.content, normalize_xml10_eols) |
921 | 0 | } |
922 | | |
923 | | /// Decodes the raw input byte content of the CDATA section of the XML 1.1 event |
924 | | /// into a string. |
925 | | /// |
926 | | /// When this event produced by the reader, it uses the encoding information |
927 | | /// associated with that reader to interpret the raw bytes contained within |
928 | | /// this CDATA event. |
929 | | /// |
930 | | /// This will allocate if the value in non-UTF-8 encoding, or EOL normalization |
931 | | /// is required. |
932 | | /// |
933 | | /// Note, that this method should be used only if event represents XML 1.1 content, |
934 | | /// because rules for normalizing EOLs for [XML 1.0], [XML 1.1] and [HTML] differs. |
935 | | /// |
936 | | /// To get HTML content use [`xml10_content()`](Self::xml10_content). |
937 | | /// |
938 | | /// [XML 1.0]: https://www.w3.org/TR/xml/#sec-line-ends |
939 | | /// [XML 1.1]: https://www.w3.org/TR/xml11/#sec-line-ends |
940 | | /// [HTML]: https://html.spec.whatwg.org/#normalize-newlines |
941 | 0 | pub fn xml11_content(&self) -> Result<Cow<'a, str>, EncodingError> { |
942 | 0 | self.decoder.content(&self.content, normalize_xml11_eols) |
943 | 0 | } |
944 | | |
945 | | /// Alias for [`xml11_content()`](Self::xml11_content). |
946 | | #[inline] |
947 | | pub fn xml_content(&self) -> Result<Cow<'a, str>, EncodingError> { |
948 | | self.xml11_content() |
949 | | } |
950 | | |
951 | | /// Alias for [`xml10_content()`](Self::xml10_content). |
952 | | #[inline] |
953 | | pub fn html_content(&self) -> Result<Cow<'a, str>, EncodingError> { |
954 | | self.xml10_content() |
955 | | } |
956 | | } |
957 | | |
958 | | impl<'a> Debug for BytesCData<'a> { |
959 | 62.8k | fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
960 | 62.8k | write!(f, "BytesCData {{ content: ")?; |
961 | 62.8k | write_cow_string(f, &self.content)?; |
962 | 62.8k | write!(f, " }}") |
963 | 62.8k | } |
964 | | } |
965 | | |
966 | | impl<'a> Deref for BytesCData<'a> { |
967 | | type Target = [u8]; |
968 | | |
969 | 70.4k | fn deref(&self) -> &[u8] { |
970 | 70.4k | &self.content |
971 | 70.4k | } |
972 | | } |
973 | | |
974 | | #[cfg(feature = "arbitrary")] |
975 | | impl<'a> arbitrary::Arbitrary<'a> for BytesCData<'a> { |
976 | 2.78k | fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> { |
977 | 2.78k | Ok(Self::new(<&str>::arbitrary(u)?)) |
978 | 2.78k | } |
979 | 0 | fn size_hint(depth: usize) -> (usize, Option<usize>) { |
980 | 0 | return <&str as arbitrary::Arbitrary>::size_hint(depth); |
981 | 0 | } |
982 | | } |
983 | | |
984 | | /// Iterator over `CDATA` sections in a string. |
985 | | /// |
986 | | /// This iterator is created by the [`BytesCData::escaped`] method. |
987 | | #[derive(Clone)] |
988 | | pub struct CDataIterator<'a> { |
989 | | /// The unprocessed data which should be emitted as `BytesCData` events. |
990 | | /// At each iteration, the processed data is cut from this slice. |
991 | | unprocessed: &'a [u8], |
992 | | finished: bool, |
993 | | } |
994 | | |
995 | | impl<'a> Debug for CDataIterator<'a> { |
996 | 0 | fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
997 | 0 | f.debug_struct("CDataIterator") |
998 | 0 | .field("unprocessed", &Bytes(self.unprocessed)) |
999 | 0 | .field("finished", &self.finished) |
1000 | 0 | .finish() |
1001 | 0 | } |
1002 | | } |
1003 | | |
1004 | | impl<'a> Iterator for CDataIterator<'a> { |
1005 | | type Item = BytesCData<'a>; |
1006 | | |
1007 | 0 | fn next(&mut self) -> Option<BytesCData<'a>> { |
1008 | 0 | if self.finished { |
1009 | 0 | return None; |
1010 | 0 | } |
1011 | | |
1012 | 0 | for gt in memchr::memchr_iter(b'>', self.unprocessed) { |
1013 | 0 | if self.unprocessed[..gt].ends_with(b"]]") { |
1014 | 0 | let (slice, rest) = self.unprocessed.split_at(gt); |
1015 | 0 | self.unprocessed = rest; |
1016 | 0 | return Some(BytesCData::wrap(slice, Decoder::utf8())); |
1017 | 0 | } |
1018 | | } |
1019 | | |
1020 | 0 | self.finished = true; |
1021 | 0 | Some(BytesCData::wrap(self.unprocessed, Decoder::utf8())) |
1022 | 0 | } |
1023 | | } |
1024 | | |
1025 | | impl FusedIterator for CDataIterator<'_> {} |
1026 | | |
1027 | | //////////////////////////////////////////////////////////////////////////////////////////////////// |
1028 | | |
1029 | | /// [Processing instructions][PI] (PIs) allow documents to contain instructions for applications. |
1030 | | /// |
1031 | | /// This event implements `Deref<Target = [u8]>`. The `deref()` implementation |
1032 | | /// returns the content of this event between `<?` and `?>`. |
1033 | | /// |
1034 | | /// Note, that inner text will not contain `?>` sequence inside: |
1035 | | /// |
1036 | | /// ``` |
1037 | | /// # use quick_xml::events::{BytesPI, Event}; |
1038 | | /// # use quick_xml::reader::Reader; |
1039 | | /// # use pretty_assertions::assert_eq; |
1040 | | /// let mut reader = Reader::from_str("<?processing instruction >:-<~ ?>"); |
1041 | | /// let content = "processing instruction >:-<~ "; |
1042 | | /// let event = BytesPI::new(content); |
1043 | | /// |
1044 | | /// assert_eq!(reader.read_event().unwrap(), Event::PI(event.borrow())); |
1045 | | /// // deref coercion of &BytesPI to &[u8] |
1046 | | /// assert_eq!(&event as &[u8], content.as_bytes()); |
1047 | | /// // AsRef<[u8]> for &T + deref coercion |
1048 | | /// assert_eq!(event.as_ref(), content.as_bytes()); |
1049 | | /// ``` |
1050 | | /// |
1051 | | /// [PI]: https://www.w3.org/TR/xml11/#sec-pi |
1052 | | #[derive(Clone, Eq, PartialEq)] |
1053 | | pub struct BytesPI<'a> { |
1054 | | content: BytesStart<'a>, |
1055 | | } |
1056 | | |
1057 | | impl<'a> BytesPI<'a> { |
1058 | | /// Creates a new `BytesPI` from a byte sequence in the specified encoding. |
1059 | | #[inline] |
1060 | 13.6k | pub(crate) const fn wrap(content: &'a [u8], target_len: usize, decoder: Decoder) -> Self { |
1061 | 13.6k | Self { |
1062 | 13.6k | content: BytesStart::wrap(content, target_len, decoder), |
1063 | 13.6k | } |
1064 | 13.6k | } |
1065 | | |
1066 | | /// Creates a new `BytesPI` from a string. |
1067 | | /// |
1068 | | /// # Warning |
1069 | | /// |
1070 | | /// `content` must not contain the `?>` sequence. |
1071 | | #[inline] |
1072 | 5.94k | pub fn new<C: Into<Cow<'a, str>>>(content: C) -> Self { |
1073 | 5.94k | let buf = str_cow_to_bytes(content); |
1074 | 5.94k | let name_len = name_len(&buf); |
1075 | 5.94k | Self { |
1076 | 5.94k | content: BytesStart { |
1077 | 5.94k | buf, |
1078 | 5.94k | name_len, |
1079 | 5.94k | decoder: Decoder::utf8(), |
1080 | 5.94k | }, |
1081 | 5.94k | } |
1082 | 5.94k | } |
1083 | | |
1084 | | /// Ensures that all data is owned to extend the object's lifetime if |
1085 | | /// necessary. |
1086 | | #[inline] |
1087 | 0 | pub fn into_owned(self) -> BytesPI<'static> { |
1088 | 0 | BytesPI { |
1089 | 0 | content: self.content.into_owned().into(), |
1090 | 0 | } |
1091 | 0 | } |
1092 | | |
1093 | | /// Extracts the inner `Cow` from the `BytesPI` event container. |
1094 | | #[inline] |
1095 | | pub fn into_inner(self) -> Cow<'a, [u8]> { |
1096 | | self.content.buf |
1097 | | } |
1098 | | |
1099 | | /// Converts the event into a borrowed event. |
1100 | | #[inline] |
1101 | 10.2k | pub fn borrow(&self) -> BytesPI<'_> { |
1102 | 10.2k | BytesPI { |
1103 | 10.2k | content: self.content.borrow(), |
1104 | 10.2k | } |
1105 | 10.2k | } <quick_xml::events::BytesPI>::borrow Line | Count | Source | 1101 | 3.05k | pub fn borrow(&self) -> BytesPI<'_> { | 1102 | 3.05k | BytesPI { | 1103 | 3.05k | content: self.content.borrow(), | 1104 | 3.05k | } | 1105 | 3.05k | } |
<quick_xml::events::BytesPI>::borrow Line | Count | Source | 1101 | 7.19k | pub fn borrow(&self) -> BytesPI<'_> { | 1102 | 7.19k | BytesPI { | 1103 | 7.19k | content: self.content.borrow(), | 1104 | 7.19k | } | 1105 | 7.19k | } |
|
1106 | | |
1107 | | /// A target used to identify the application to which the instruction is directed. |
1108 | | /// |
1109 | | /// # Example |
1110 | | /// |
1111 | | /// ``` |
1112 | | /// # use pretty_assertions::assert_eq; |
1113 | | /// use quick_xml::events::BytesPI; |
1114 | | /// |
1115 | | /// let instruction = BytesPI::new(r#"xml-stylesheet href="style.css""#); |
1116 | | /// assert_eq!(instruction.target(), b"xml-stylesheet"); |
1117 | | /// ``` |
1118 | | #[inline] |
1119 | | pub fn target(&self) -> &[u8] { |
1120 | | self.content.name().0 |
1121 | | } |
1122 | | |
1123 | | /// Content of the processing instruction. Contains everything between target |
1124 | | /// name and the end of the instruction. A direct consequence is that the first |
1125 | | /// character is always a space character. |
1126 | | /// |
1127 | | /// # Example |
1128 | | /// |
1129 | | /// ``` |
1130 | | /// # use pretty_assertions::assert_eq; |
1131 | | /// use quick_xml::events::BytesPI; |
1132 | | /// |
1133 | | /// let instruction = BytesPI::new(r#"xml-stylesheet href="style.css""#); |
1134 | | /// assert_eq!(instruction.content(), br#" href="style.css""#); |
1135 | | /// ``` |
1136 | | #[inline] |
1137 | | pub fn content(&self) -> &[u8] { |
1138 | | self.content.attributes_raw() |
1139 | | } |
1140 | | |
1141 | | /// A view of the processing instructions' content as a list of key-value pairs. |
1142 | | /// |
1143 | | /// Key-value pairs are used in some processing instructions, for example in |
1144 | | /// `<?xml-stylesheet?>`. |
1145 | | /// |
1146 | | /// Returned iterator does not validate attribute values as may required by |
1147 | | /// target's rules. For example, it doesn't check that substring `?>` is not |
1148 | | /// present in the attribute value. That shouldn't be the problem when event |
1149 | | /// is produced by the reader, because reader detects end of processing instruction |
1150 | | /// by the first `?>` sequence, as required by the specification, and therefore |
1151 | | /// this sequence cannot appear inside it. |
1152 | | /// |
1153 | | /// # Example |
1154 | | /// |
1155 | | /// ``` |
1156 | | /// # use pretty_assertions::assert_eq; |
1157 | | /// use std::borrow::Cow; |
1158 | | /// use quick_xml::events::attributes::Attribute; |
1159 | | /// use quick_xml::events::BytesPI; |
1160 | | /// use quick_xml::name::QName; |
1161 | | /// |
1162 | | /// let instruction = BytesPI::new(r#"xml-stylesheet href="style.css""#); |
1163 | | /// for attr in instruction.attributes() { |
1164 | | /// assert_eq!(attr, Ok(Attribute { |
1165 | | /// key: QName(b"href"), |
1166 | | /// value: Cow::Borrowed(b"style.css"), |
1167 | | /// })); |
1168 | | /// } |
1169 | | /// ``` |
1170 | | #[inline] |
1171 | | pub fn attributes(&self) -> Attributes<'_> { |
1172 | | self.content.attributes() |
1173 | | } |
1174 | | } |
1175 | | |
1176 | | impl<'a> Debug for BytesPI<'a> { |
1177 | 7.19k | fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
1178 | 7.19k | write!(f, "BytesPI {{ content: ")?; |
1179 | 7.19k | write_cow_string(f, &self.content.buf)?; |
1180 | 7.19k | write!(f, " }}") |
1181 | 7.19k | } |
1182 | | } |
1183 | | |
1184 | | impl<'a> Deref for BytesPI<'a> { |
1185 | | type Target = [u8]; |
1186 | | |
1187 | 9.54k | fn deref(&self) -> &[u8] { |
1188 | 9.54k | &self.content |
1189 | 9.54k | } |
1190 | | } |
1191 | | |
1192 | | #[cfg(feature = "arbitrary")] |
1193 | | impl<'a> arbitrary::Arbitrary<'a> for BytesPI<'a> { |
1194 | 3.05k | fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> { |
1195 | 3.05k | Ok(Self::new(<&str>::arbitrary(u)?)) |
1196 | 3.05k | } |
1197 | 0 | fn size_hint(depth: usize) -> (usize, Option<usize>) { |
1198 | 0 | return <&str as arbitrary::Arbitrary>::size_hint(depth); |
1199 | 0 | } |
1200 | | } |
1201 | | |
1202 | | //////////////////////////////////////////////////////////////////////////////////////////////////// |
1203 | | |
1204 | | /// An XML declaration (`Event::Decl`). |
1205 | | /// |
1206 | | /// [W3C XML 1.1 Prolog and Document Type Declaration](http://w3.org/TR/xml11/#sec-prolog-dtd) |
1207 | | /// |
1208 | | /// This event implements `Deref<Target = [u8]>`. The `deref()` implementation |
1209 | | /// returns the content of this event between `<?` and `?>`. |
1210 | | /// |
1211 | | /// Note, that inner text will not contain `?>` sequence inside: |
1212 | | /// |
1213 | | /// ``` |
1214 | | /// # use quick_xml::events::{BytesDecl, BytesStart, Event}; |
1215 | | /// # use quick_xml::reader::Reader; |
1216 | | /// # use pretty_assertions::assert_eq; |
1217 | | /// let mut reader = Reader::from_str("<?xml version = '1.0' ?>"); |
1218 | | /// let content = "xml version = '1.0' "; |
1219 | | /// let event = BytesDecl::from_start(BytesStart::from_content(content, 3)); |
1220 | | /// |
1221 | | /// assert_eq!(reader.read_event().unwrap(), Event::Decl(event.borrow())); |
1222 | | /// // deref coercion of &BytesDecl to &[u8] |
1223 | | /// assert_eq!(&event as &[u8], content.as_bytes()); |
1224 | | /// // AsRef<[u8]> for &T + deref coercion |
1225 | | /// assert_eq!(event.as_ref(), content.as_bytes()); |
1226 | | /// ``` |
1227 | | #[derive(Clone, Debug, Eq, PartialEq)] |
1228 | | pub struct BytesDecl<'a> { |
1229 | | content: BytesStart<'a>, |
1230 | | } |
1231 | | |
1232 | | impl<'a> BytesDecl<'a> { |
1233 | | /// Constructs a new `XmlDecl` from the (mandatory) _version_ (should be `1.0` or `1.1`), |
1234 | | /// the optional _encoding_ (e.g., `UTF-8`) and the optional _standalone_ (`yes` or `no`) |
1235 | | /// attribute. |
1236 | | /// |
1237 | | /// Does not escape any of its inputs. Always uses double quotes to wrap the attribute values. |
1238 | | /// The caller is responsible for escaping attribute values. Shouldn't usually be relevant since |
1239 | | /// the double quote character is not allowed in any of the attribute values. |
1240 | 5.38k | pub fn new( |
1241 | 5.38k | version: &str, |
1242 | 5.38k | encoding: Option<&str>, |
1243 | 5.38k | standalone: Option<&str>, |
1244 | 5.38k | ) -> BytesDecl<'static> { |
1245 | | // Compute length of the buffer based on supplied attributes |
1246 | | // ' encoding=""' => 12 |
1247 | 5.38k | let encoding_attr_len = if let Some(xs) = encoding { |
1248 | 3.00k | 12 + xs.len() |
1249 | | } else { |
1250 | 2.37k | 0 |
1251 | | }; |
1252 | | // ' standalone=""' => 14 |
1253 | 5.38k | let standalone_attr_len = if let Some(xs) = standalone { |
1254 | 3.09k | 14 + xs.len() |
1255 | | } else { |
1256 | 2.28k | 0 |
1257 | | }; |
1258 | | // 'xml version=""' => 14 |
1259 | 5.38k | let mut buf = String::with_capacity(14 + encoding_attr_len + standalone_attr_len); |
1260 | | |
1261 | 5.38k | buf.push_str("xml version=\""); |
1262 | 5.38k | buf.push_str(version); |
1263 | | |
1264 | 5.38k | if let Some(encoding_val) = encoding { |
1265 | 3.00k | buf.push_str("\" encoding=\""); |
1266 | 3.00k | buf.push_str(encoding_val); |
1267 | 3.00k | } |
1268 | | |
1269 | 5.38k | if let Some(standalone_val) = standalone { |
1270 | 3.09k | buf.push_str("\" standalone=\""); |
1271 | 3.09k | buf.push_str(standalone_val); |
1272 | 3.09k | } |
1273 | 5.38k | buf.push('"'); |
1274 | | |
1275 | 5.38k | BytesDecl { |
1276 | 5.38k | content: BytesStart::from_content(buf, 3), |
1277 | 5.38k | } |
1278 | 5.38k | } |
1279 | | |
1280 | | /// Creates a `BytesDecl` from a `BytesStart` |
1281 | 21.2k | pub const fn from_start(start: BytesStart<'a>) -> Self { |
1282 | 21.2k | Self { content: start } |
1283 | 21.2k | } |
1284 | | |
1285 | | /// Gets xml version, excluding quotes (`'` or `"`). |
1286 | | /// |
1287 | | /// According to the [grammar], the version *must* be the first thing in the declaration. |
1288 | | /// This method tries to extract the first thing in the declaration and return it. |
1289 | | /// In case of multiple attributes value of the first one is returned. |
1290 | | /// |
1291 | | /// If version is missed in the declaration, or the first thing is not a version, |
1292 | | /// [`IllFormedError::MissingDeclVersion`] will be returned. |
1293 | | /// |
1294 | | /// # Examples |
1295 | | /// |
1296 | | /// ``` |
1297 | | /// use quick_xml::errors::{Error, IllFormedError}; |
1298 | | /// use quick_xml::events::{BytesDecl, BytesStart}; |
1299 | | /// |
1300 | | /// // <?xml version='1.1'?> |
1301 | | /// let decl = BytesDecl::from_start(BytesStart::from_content(" version='1.1'", 0)); |
1302 | | /// assert_eq!(decl.version().unwrap(), b"1.1".as_ref()); |
1303 | | /// |
1304 | | /// // <?xml version='1.0' version='1.1'?> |
1305 | | /// let decl = BytesDecl::from_start(BytesStart::from_content(" version='1.0' version='1.1'", 0)); |
1306 | | /// assert_eq!(decl.version().unwrap(), b"1.0".as_ref()); |
1307 | | /// |
1308 | | /// // <?xml encoding='utf-8'?> |
1309 | | /// let decl = BytesDecl::from_start(BytesStart::from_content(" encoding='utf-8'", 0)); |
1310 | | /// match decl.version() { |
1311 | | /// Err(Error::IllFormed(IllFormedError::MissingDeclVersion(Some(key)))) => assert_eq!(key, "encoding"), |
1312 | | /// _ => assert!(false), |
1313 | | /// } |
1314 | | /// |
1315 | | /// // <?xml encoding='utf-8' version='1.1'?> |
1316 | | /// let decl = BytesDecl::from_start(BytesStart::from_content(" encoding='utf-8' version='1.1'", 0)); |
1317 | | /// match decl.version() { |
1318 | | /// Err(Error::IllFormed(IllFormedError::MissingDeclVersion(Some(key)))) => assert_eq!(key, "encoding"), |
1319 | | /// _ => assert!(false), |
1320 | | /// } |
1321 | | /// |
1322 | | /// // <?xml?> |
1323 | | /// let decl = BytesDecl::from_start(BytesStart::from_content("", 0)); |
1324 | | /// match decl.version() { |
1325 | | /// Err(Error::IllFormed(IllFormedError::MissingDeclVersion(None))) => {}, |
1326 | | /// _ => assert!(false), |
1327 | | /// } |
1328 | | /// ``` |
1329 | | /// |
1330 | | /// [grammar]: https://www.w3.org/TR/xml11/#NT-XMLDecl |
1331 | 14.5k | pub fn version(&self) -> Result<Cow<'_, [u8]>, Error> { |
1332 | | // The version *must* be the first thing in the declaration. |
1333 | 14.5k | match self.content.attributes().with_checks(false).next() { |
1334 | 6.10k | Some(Ok(a)) if a.key.as_ref() == b"version" => Ok(a.value), |
1335 | | // first attribute was not "version" |
1336 | 2.84k | Some(Ok(a)) => { |
1337 | 2.84k | let found = from_utf8(a.key.as_ref()) |
1338 | 2.84k | .map_err(|_| IllFormedError::MissingDeclVersion(None))? |
1339 | 2.51k | .to_string(); |
1340 | 2.51k | Err(Error::IllFormed(IllFormedError::MissingDeclVersion(Some( |
1341 | 2.51k | found, |
1342 | 2.51k | )))) |
1343 | | } |
1344 | | // error parsing attributes |
1345 | 3.81k | Some(Err(e)) => Err(e.into()), |
1346 | | // no attributes |
1347 | 4.65k | None => Err(Error::IllFormed(IllFormedError::MissingDeclVersion(None))), |
1348 | | } |
1349 | 14.5k | } |
1350 | | |
1351 | | /// Gets xml encoding, excluding quotes (`'` or `"`). |
1352 | | /// |
1353 | | /// Although according to the [grammar] encoding must appear before `"standalone"` |
1354 | | /// and after `"version"`, this method does not check that. The first occurrence |
1355 | | /// of the attribute will be returned even if there are several. Also, method does |
1356 | | /// not restrict symbols that can forming the encoding, so the returned encoding |
1357 | | /// name may not correspond to the grammar. |
1358 | | /// |
1359 | | /// # Examples |
1360 | | /// |
1361 | | /// ``` |
1362 | | /// use std::borrow::Cow; |
1363 | | /// use quick_xml::Error; |
1364 | | /// use quick_xml::events::{BytesDecl, BytesStart}; |
1365 | | /// |
1366 | | /// // <?xml version='1.1'?> |
1367 | | /// let decl = BytesDecl::from_start(BytesStart::from_content(" version='1.1'", 0)); |
1368 | | /// assert!(decl.encoding().is_none()); |
1369 | | /// |
1370 | | /// // <?xml encoding='utf-8'?> |
1371 | | /// let decl = BytesDecl::from_start(BytesStart::from_content(" encoding='utf-8'", 0)); |
1372 | | /// match decl.encoding() { |
1373 | | /// Some(Ok(Cow::Borrowed(encoding))) => assert_eq!(encoding, b"utf-8"), |
1374 | | /// _ => assert!(false), |
1375 | | /// } |
1376 | | /// |
1377 | | /// // <?xml encoding='something_WRONG' encoding='utf-8'?> |
1378 | | /// let decl = BytesDecl::from_start(BytesStart::from_content(" encoding='something_WRONG' encoding='utf-8'", 0)); |
1379 | | /// match decl.encoding() { |
1380 | | /// Some(Ok(Cow::Borrowed(encoding))) => assert_eq!(encoding, b"something_WRONG"), |
1381 | | /// _ => assert!(false), |
1382 | | /// } |
1383 | | /// ``` |
1384 | | /// |
1385 | | /// [grammar]: https://www.w3.org/TR/xml11/#NT-XMLDecl |
1386 | 14.5k | pub fn encoding(&self) -> Option<Result<Cow<'_, [u8]>, AttrError>> { |
1387 | 14.5k | self.content |
1388 | 14.5k | .try_get_attribute("encoding") |
1389 | 14.5k | .map(|a| a.map(|a| a.value)) |
1390 | 14.5k | .transpose() |
1391 | 14.5k | } |
1392 | | |
1393 | | /// Gets xml standalone, excluding quotes (`'` or `"`). |
1394 | | /// |
1395 | | /// Although according to the [grammar] standalone flag must appear after `"version"` |
1396 | | /// and `"encoding"`, this method does not check that. The first occurrence of the |
1397 | | /// attribute will be returned even if there are several. Also, method does not |
1398 | | /// restrict symbols that can forming the value, so the returned flag name may not |
1399 | | /// correspond to the grammar. |
1400 | | /// |
1401 | | /// # Examples |
1402 | | /// |
1403 | | /// ``` |
1404 | | /// use std::borrow::Cow; |
1405 | | /// use quick_xml::Error; |
1406 | | /// use quick_xml::events::{BytesDecl, BytesStart}; |
1407 | | /// |
1408 | | /// // <?xml version='1.1'?> |
1409 | | /// let decl = BytesDecl::from_start(BytesStart::from_content(" version='1.1'", 0)); |
1410 | | /// assert!(decl.standalone().is_none()); |
1411 | | /// |
1412 | | /// // <?xml standalone='yes'?> |
1413 | | /// let decl = BytesDecl::from_start(BytesStart::from_content(" standalone='yes'", 0)); |
1414 | | /// match decl.standalone() { |
1415 | | /// Some(Ok(Cow::Borrowed(encoding))) => assert_eq!(encoding, b"yes"), |
1416 | | /// _ => assert!(false), |
1417 | | /// } |
1418 | | /// |
1419 | | /// // <?xml standalone='something_WRONG' encoding='utf-8'?> |
1420 | | /// let decl = BytesDecl::from_start(BytesStart::from_content(" standalone='something_WRONG' encoding='utf-8'", 0)); |
1421 | | /// match decl.standalone() { |
1422 | | /// Some(Ok(Cow::Borrowed(flag))) => assert_eq!(flag, b"something_WRONG"), |
1423 | | /// _ => assert!(false), |
1424 | | /// } |
1425 | | /// ``` |
1426 | | /// |
1427 | | /// [grammar]: https://www.w3.org/TR/xml11/#NT-XMLDecl |
1428 | 14.5k | pub fn standalone(&self) -> Option<Result<Cow<'_, [u8]>, AttrError>> { |
1429 | 14.5k | self.content |
1430 | 14.5k | .try_get_attribute("standalone") |
1431 | 14.5k | .map(|a| a.map(|a| a.value)) |
1432 | 14.5k | .transpose() |
1433 | 14.5k | } |
1434 | | |
1435 | | /// Gets the actual encoding using [_get an encoding_](https://encoding.spec.whatwg.org/#concept-encoding-get) |
1436 | | /// algorithm. |
1437 | | /// |
1438 | | /// If encoding in not known, or `encoding` key was not found, returns `None`. |
1439 | | /// In case of duplicated `encoding` key, encoding, corresponding to the first |
1440 | | /// one, is returned. |
1441 | | #[cfg(feature = "encoding")] |
1442 | | pub fn encoder(&self) -> Option<&'static Encoding> { |
1443 | | self.encoding() |
1444 | | .and_then(|e| e.ok()) |
1445 | | .and_then(|e| Encoding::for_label(&e)) |
1446 | | } |
1447 | | |
1448 | | /// Converts the event into an owned event. |
1449 | 0 | pub fn into_owned(self) -> BytesDecl<'static> { |
1450 | 0 | BytesDecl { |
1451 | 0 | content: self.content.into_owned(), |
1452 | 0 | } |
1453 | 0 | } |
1454 | | |
1455 | | /// Converts the event into a borrowed event. |
1456 | | #[inline] |
1457 | 34.5k | pub fn borrow(&self) -> BytesDecl<'_> { |
1458 | 34.5k | BytesDecl { |
1459 | 34.5k | content: self.content.borrow(), |
1460 | 34.5k | } |
1461 | 34.5k | } <quick_xml::events::BytesDecl>::borrow Line | Count | Source | 1457 | 5.34k | pub fn borrow(&self) -> BytesDecl<'_> { | 1458 | 5.34k | BytesDecl { | 1459 | 5.34k | content: self.content.borrow(), | 1460 | 5.34k | } | 1461 | 5.34k | } |
<quick_xml::events::BytesDecl>::borrow Line | Count | Source | 1457 | 29.1k | pub fn borrow(&self) -> BytesDecl<'_> { | 1458 | 29.1k | BytesDecl { | 1459 | 29.1k | content: self.content.borrow(), | 1460 | 29.1k | } | 1461 | 29.1k | } |
|
1462 | | } |
1463 | | |
1464 | | impl<'a> Deref for BytesDecl<'a> { |
1465 | | type Target = [u8]; |
1466 | | |
1467 | 19.9k | fn deref(&self) -> &[u8] { |
1468 | 19.9k | &self.content |
1469 | 19.9k | } |
1470 | | } |
1471 | | |
1472 | | #[cfg(feature = "arbitrary")] |
1473 | | impl<'a> arbitrary::Arbitrary<'a> for BytesDecl<'a> { |
1474 | 5.38k | fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> { |
1475 | 5.38k | Ok(Self::new( |
1476 | 5.38k | <&str>::arbitrary(u)?, |
1477 | 5.38k | Option::<&str>::arbitrary(u)?, |
1478 | 5.38k | Option::<&str>::arbitrary(u)?, |
1479 | | )) |
1480 | 5.38k | } |
1481 | | |
1482 | 0 | fn size_hint(depth: usize) -> (usize, Option<usize>) { |
1483 | 0 | return <&str as arbitrary::Arbitrary>::size_hint(depth); |
1484 | 0 | } |
1485 | | } |
1486 | | |
1487 | | //////////////////////////////////////////////////////////////////////////////////////////////////// |
1488 | | |
1489 | | /// Character or general entity reference (`Event::GeneralRef`): `&ref;` or `&#<number>;`. |
1490 | | /// |
1491 | | /// This event implements `Deref<Target = [u8]>`. The `deref()` implementation |
1492 | | /// returns the content of this event between `&` and `;`: |
1493 | | /// |
1494 | | /// ``` |
1495 | | /// # use quick_xml::events::{BytesRef, Event}; |
1496 | | /// # use quick_xml::reader::Reader; |
1497 | | /// # use pretty_assertions::assert_eq; |
1498 | | /// let mut reader = Reader::from_str(r#"&entity;"#); |
1499 | | /// let content = "entity"; |
1500 | | /// let event = BytesRef::new(content); |
1501 | | /// |
1502 | | /// assert_eq!(reader.read_event().unwrap(), Event::GeneralRef(event.borrow())); |
1503 | | /// // deref coercion of &BytesRef to &[u8] |
1504 | | /// assert_eq!(&event as &[u8], content.as_bytes()); |
1505 | | /// // AsRef<[u8]> for &T + deref coercion |
1506 | | /// assert_eq!(event.as_ref(), content.as_bytes()); |
1507 | | /// ``` |
1508 | | #[derive(Clone, Eq, PartialEq)] |
1509 | | pub struct BytesRef<'a> { |
1510 | | content: Cow<'a, [u8]>, |
1511 | | /// Encoding in which the `content` is stored inside the event. |
1512 | | decoder: Decoder, |
1513 | | } |
1514 | | |
1515 | | impl<'a> BytesRef<'a> { |
1516 | | /// Internal constructor, used by `Reader`. Supplies data in reader's encoding |
1517 | | #[inline] |
1518 | 11.5M | pub(crate) const fn wrap(content: &'a [u8], decoder: Decoder) -> Self { |
1519 | 11.5M | Self { |
1520 | 11.5M | content: Cow::Borrowed(content), |
1521 | 11.5M | decoder, |
1522 | 11.5M | } |
1523 | 11.5M | } <quick_xml::events::BytesRef>::wrap Line | Count | Source | 1518 | 11.3M | pub(crate) const fn wrap(content: &'a [u8], decoder: Decoder) -> Self { | 1519 | 11.3M | Self { | 1520 | 11.3M | content: Cow::Borrowed(content), | 1521 | 11.3M | decoder, | 1522 | 11.3M | } | 1523 | 11.3M | } |
<quick_xml::events::BytesRef>::wrap Line | Count | Source | 1518 | 172k | pub(crate) const fn wrap(content: &'a [u8], decoder: Decoder) -> Self { | 1519 | 172k | Self { | 1520 | 172k | content: Cow::Borrowed(content), | 1521 | 172k | decoder, | 1522 | 172k | } | 1523 | 172k | } |
|
1524 | | |
1525 | | /// Creates a new `BytesRef` borrowing a slice. |
1526 | | /// |
1527 | | /// # Warning |
1528 | | /// |
1529 | | /// `name` must be a valid name. |
1530 | | #[inline] |
1531 | 462 | pub fn new<C: Into<Cow<'a, str>>>(name: C) -> Self { |
1532 | 462 | Self { |
1533 | 462 | content: str_cow_to_bytes(name), |
1534 | 462 | decoder: Decoder::utf8(), |
1535 | 462 | } |
1536 | 462 | } |
1537 | | |
1538 | | /// Converts the event into an owned event. |
1539 | 0 | pub fn into_owned(self) -> BytesRef<'static> { |
1540 | 0 | BytesRef { |
1541 | 0 | content: Cow::Owned(self.content.into_owned()), |
1542 | 0 | decoder: self.decoder, |
1543 | 0 | } |
1544 | 0 | } |
1545 | | |
1546 | | /// Extracts the inner `Cow` from the `BytesRef` event container. |
1547 | | #[inline] |
1548 | | pub fn into_inner(self) -> Cow<'a, [u8]> { |
1549 | | self.content |
1550 | | } |
1551 | | |
1552 | | /// Converts the event into a borrowed event. |
1553 | | #[inline] |
1554 | 345k | pub fn borrow(&self) -> BytesRef<'_> { |
1555 | 345k | BytesRef { |
1556 | 345k | content: Cow::Borrowed(&self.content), |
1557 | 345k | decoder: self.decoder, |
1558 | 345k | } |
1559 | 345k | } <quick_xml::events::BytesRef>::borrow Line | Count | Source | 1554 | 440 | pub fn borrow(&self) -> BytesRef<'_> { | 1555 | 440 | BytesRef { | 1556 | 440 | content: Cow::Borrowed(&self.content), | 1557 | 440 | decoder: self.decoder, | 1558 | 440 | } | 1559 | 440 | } |
<quick_xml::events::BytesRef>::borrow Line | Count | Source | 1554 | 345k | pub fn borrow(&self) -> BytesRef<'_> { | 1555 | 345k | BytesRef { | 1556 | 345k | content: Cow::Borrowed(&self.content), | 1557 | 345k | decoder: self.decoder, | 1558 | 345k | } | 1559 | 345k | } |
|
1560 | | |
1561 | | /// Decodes the content of the event. |
1562 | | /// |
1563 | | /// This will allocate if the value contains any escape sequences or in |
1564 | | /// non-UTF-8 encoding. |
1565 | | /// |
1566 | | /// This method does not normalizes end-of-line characters as required by [specification]. |
1567 | | /// Usually you need [`xml_content()`](Self::xml_content) instead of this method. |
1568 | | /// |
1569 | | /// [specification]: https://www.w3.org/TR/xml11/#sec-line-ends |
1570 | 172k | pub fn decode(&self) -> Result<Cow<'a, str>, EncodingError> { |
1571 | 172k | self.decoder.decode_cow(&self.content) |
1572 | 172k | } |
1573 | | |
1574 | | /// Decodes the content of the XML 1.0 or HTML event. |
1575 | | /// |
1576 | | /// When this event produced by the reader, it uses the encoding information |
1577 | | /// associated with that reader to interpret the raw bytes contained within |
1578 | | /// this general reference event. |
1579 | | /// |
1580 | | /// This will allocate if the value in non-UTF-8 encoding, or EOL normalization |
1581 | | /// is required. |
1582 | | /// |
1583 | | /// Note, that this method should be used only if event represents XML 1.0 or HTML content, |
1584 | | /// because rules for normalizing EOLs for [XML 1.0] / [HTML] and [XML 1.1] differs. |
1585 | | /// |
1586 | | /// This method also can be used to get HTML content, because rules the same. |
1587 | | /// |
1588 | | /// [XML 1.0]: https://www.w3.org/TR/xml/#sec-line-ends |
1589 | | /// [XML 1.1]: https://www.w3.org/TR/xml11/#sec-line-ends |
1590 | | /// [HTML]: https://html.spec.whatwg.org/#normalize-newlines |
1591 | 0 | pub fn xml10_content(&self) -> Result<Cow<'a, str>, EncodingError> { |
1592 | 0 | self.decoder.content(&self.content, normalize_xml10_eols) |
1593 | 0 | } |
1594 | | |
1595 | | /// Decodes the content of the XML 1.1 event. |
1596 | | /// |
1597 | | /// When this event produced by the reader, it uses the encoding information |
1598 | | /// associated with that reader to interpret the raw bytes contained within |
1599 | | /// this general reference event. |
1600 | | /// |
1601 | | /// This will allocate if the value in non-UTF-8 encoding, or EOL normalization |
1602 | | /// is required. |
1603 | | /// |
1604 | | /// Note, that this method should be used only if event represents XML 1.1 content, |
1605 | | /// because rules for normalizing EOLs for [XML 1.0] / [HTML] and [XML 1.1] differs. |
1606 | | /// |
1607 | | /// To get HTML content use [`xml10_content()`](Self::xml10_content). |
1608 | | /// |
1609 | | /// [XML 1.0]: https://www.w3.org/TR/xml/#sec-line-ends |
1610 | | /// [XML 1.1]: https://www.w3.org/TR/xml11/#sec-line-ends |
1611 | | /// [HTML]: https://html.spec.whatwg.org/#normalize-newlines |
1612 | 0 | pub fn xml11_content(&self) -> Result<Cow<'a, str>, EncodingError> { |
1613 | 0 | self.decoder.content(&self.content, normalize_xml11_eols) |
1614 | 0 | } |
1615 | | |
1616 | | /// Alias for [`xml11_content()`](Self::xml11_content). |
1617 | | #[inline] |
1618 | | pub fn xml_content(&self) -> Result<Cow<'a, str>, EncodingError> { |
1619 | | self.xml11_content() |
1620 | | } |
1621 | | |
1622 | | /// Alias for [`xml10_content()`](Self::xml10_content). |
1623 | | #[inline] |
1624 | | pub fn html_content(&self) -> Result<Cow<'a, str>, EncodingError> { |
1625 | | self.xml10_content() |
1626 | | } |
1627 | | |
1628 | | /// Returns `true` if the specified reference represents the character reference |
1629 | | /// (`&#<number>;`). |
1630 | | /// |
1631 | | /// ``` |
1632 | | /// # use quick_xml::events::BytesRef; |
1633 | | /// # use pretty_assertions::assert_eq; |
1634 | | /// assert_eq!(BytesRef::new("#x30").is_char_ref(), true); |
1635 | | /// assert_eq!(BytesRef::new("#49" ).is_char_ref(), true); |
1636 | | /// assert_eq!(BytesRef::new("lt" ).is_char_ref(), false); |
1637 | | /// ``` |
1638 | 172k | pub fn is_char_ref(&self) -> bool { |
1639 | 172k | matches!(self.content.first(), Some(b'#')) |
1640 | 172k | } |
1641 | | |
1642 | | /// If this reference represents character reference, then resolves it and |
1643 | | /// returns the character, otherwise returns `None`. |
1644 | | /// |
1645 | | /// This method does not check if character is allowed for XML, in other words, |
1646 | | /// well-formedness constraint [WFC: Legal Char] is not enforced. |
1647 | | /// The character `0x0`, however, will return `EscapeError::InvalidCharRef`. |
1648 | | /// |
1649 | | /// ``` |
1650 | | /// # use quick_xml::events::BytesRef; |
1651 | | /// # use pretty_assertions::assert_eq; |
1652 | | /// assert_eq!(BytesRef::new("#x30").resolve_char_ref().unwrap(), Some('0')); |
1653 | | /// assert_eq!(BytesRef::new("#49" ).resolve_char_ref().unwrap(), Some('1')); |
1654 | | /// assert_eq!(BytesRef::new("lt" ).resolve_char_ref().unwrap(), None); |
1655 | | /// ``` |
1656 | | /// |
1657 | | /// [WFC: Legal Char]: https://www.w3.org/TR/xml11/#wf-Legalchar |
1658 | 172k | pub fn resolve_char_ref(&self) -> Result<Option<char>, Error> { |
1659 | 172k | if let Some(num) = self.decode()?.strip_prefix('#') { |
1660 | 134k | let ch = parse_number(num).map_err(EscapeError::InvalidCharRef)?; |
1661 | 96.4k | return Ok(Some(ch)); |
1662 | 34.5k | } |
1663 | 34.5k | Ok(None) |
1664 | 172k | } |
1665 | | } |
1666 | | |
1667 | | impl<'a> Debug for BytesRef<'a> { |
1668 | 345k | fn fmt(&self, f: &mut Formatter) -> fmt::Result { |
1669 | 345k | write!(f, "BytesRef {{ content: ")?; |
1670 | 345k | write_cow_string(f, &self.content)?; |
1671 | 345k | write!(f, " }}") |
1672 | 345k | } |
1673 | | } |
1674 | | |
1675 | | impl<'a> Deref for BytesRef<'a> { |
1676 | | type Target = [u8]; |
1677 | | |
1678 | 173k | fn deref(&self) -> &[u8] { |
1679 | 173k | &self.content |
1680 | 173k | } |
1681 | | } |
1682 | | |
1683 | | #[cfg(feature = "arbitrary")] |
1684 | | impl<'a> arbitrary::Arbitrary<'a> for BytesRef<'a> { |
1685 | 462 | fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> { |
1686 | 462 | Ok(Self::new(<&str>::arbitrary(u)?)) |
1687 | 462 | } |
1688 | | |
1689 | 0 | fn size_hint(depth: usize) -> (usize, Option<usize>) { |
1690 | 0 | <&str as arbitrary::Arbitrary>::size_hint(depth) |
1691 | 0 | } |
1692 | | } |
1693 | | |
1694 | | //////////////////////////////////////////////////////////////////////////////////////////////////// |
1695 | | |
1696 | | /// Event emitted by [`Reader::read_event_into`]. |
1697 | | /// |
1698 | | /// [`Reader::read_event_into`]: crate::reader::Reader::read_event_into |
1699 | | #[derive(Clone, Debug, Eq, PartialEq)] |
1700 | | #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] |
1701 | | pub enum Event<'a> { |
1702 | | /// Start tag (with attributes) `<tag attr="value">`. |
1703 | | Start(BytesStart<'a>), |
1704 | | /// End tag `</tag>`. |
1705 | | End(BytesEnd<'a>), |
1706 | | /// Empty element tag (with attributes) `<tag attr="value" />`. |
1707 | | Empty(BytesStart<'a>), |
1708 | | /// Escaped character data between tags. |
1709 | | Text(BytesText<'a>), |
1710 | | /// Unescaped character data stored in `<![CDATA[...]]>`. |
1711 | | CData(BytesCData<'a>), |
1712 | | /// Comment `<!-- ... -->`. |
1713 | | Comment(BytesText<'a>), |
1714 | | /// XML declaration `<?xml ...?>`. |
1715 | | Decl(BytesDecl<'a>), |
1716 | | /// Processing instruction `<?...?>`. |
1717 | | PI(BytesPI<'a>), |
1718 | | /// Document type definition data (DTD) stored in `<!DOCTYPE ...>`. |
1719 | | DocType(BytesText<'a>), |
1720 | | /// General reference `&entity;` in the textual data. Can be either an entity |
1721 | | /// reference, or a character reference. |
1722 | | GeneralRef(BytesRef<'a>), |
1723 | | /// End of XML document. |
1724 | | Eof, |
1725 | | } |
1726 | | |
1727 | | impl<'a> Event<'a> { |
1728 | | /// Converts the event to an owned version, untied to the lifetime of |
1729 | | /// buffer used when reading but incurring a new, separate allocation. |
1730 | 0 | pub fn into_owned(self) -> Event<'static> { |
1731 | 0 | match self { |
1732 | 0 | Event::Start(e) => Event::Start(e.into_owned()), |
1733 | 0 | Event::End(e) => Event::End(e.into_owned()), |
1734 | 0 | Event::Empty(e) => Event::Empty(e.into_owned()), |
1735 | 0 | Event::Text(e) => Event::Text(e.into_owned()), |
1736 | 0 | Event::Comment(e) => Event::Comment(e.into_owned()), |
1737 | 0 | Event::CData(e) => Event::CData(e.into_owned()), |
1738 | 0 | Event::Decl(e) => Event::Decl(e.into_owned()), |
1739 | 0 | Event::PI(e) => Event::PI(e.into_owned()), |
1740 | 0 | Event::DocType(e) => Event::DocType(e.into_owned()), |
1741 | 0 | Event::GeneralRef(e) => Event::GeneralRef(e.into_owned()), |
1742 | 0 | Event::Eof => Event::Eof, |
1743 | | } |
1744 | 0 | } |
1745 | | |
1746 | | /// Converts the event into a borrowed event. |
1747 | | #[inline] |
1748 | 14.5M | pub fn borrow(&self) -> Event<'_> { |
1749 | 14.5M | match self { |
1750 | 11.3M | Event::Start(e) => Event::Start(e.borrow()), |
1751 | 2.24M | Event::End(e) => Event::End(e.borrow()), |
1752 | 2.35k | Event::Empty(e) => Event::Empty(e.borrow()), |
1753 | 441k | Event::Text(e) => Event::Text(e.borrow()), |
1754 | 5.60k | Event::Comment(e) => Event::Comment(e.borrow()), |
1755 | 128k | Event::CData(e) => Event::CData(e.borrow()), |
1756 | 34.5k | Event::Decl(e) => Event::Decl(e.borrow()), |
1757 | 10.2k | Event::PI(e) => Event::PI(e.borrow()), |
1758 | 3.71k | Event::DocType(e) => Event::DocType(e.borrow()), |
1759 | 345k | Event::GeneralRef(e) => Event::GeneralRef(e.borrow()), |
1760 | 16.3k | Event::Eof => Event::Eof, |
1761 | | } |
1762 | 14.5M | } <quick_xml::events::Event>::borrow Line | Count | Source | 1748 | 21.6k | pub fn borrow(&self) -> Event<'_> { | 1749 | 21.6k | match self { | 1750 | 1.06k | Event::Start(e) => Event::Start(e.borrow()), | 1751 | 1.68k | Event::End(e) => Event::End(e.borrow()), | 1752 | 2.35k | Event::Empty(e) => Event::Empty(e.borrow()), | 1753 | 1.27k | Event::Text(e) => Event::Text(e.borrow()), | 1754 | 2.63k | Event::Comment(e) => Event::Comment(e.borrow()), | 1755 | 2.77k | Event::CData(e) => Event::CData(e.borrow()), | 1756 | 5.34k | Event::Decl(e) => Event::Decl(e.borrow()), | 1757 | 3.05k | Event::PI(e) => Event::PI(e.borrow()), | 1758 | 499 | Event::DocType(e) => Event::DocType(e.borrow()), | 1759 | 440 | Event::GeneralRef(e) => Event::GeneralRef(e.borrow()), | 1760 | 495 | Event::Eof => Event::Eof, | 1761 | | } | 1762 | 21.6k | } |
<quick_xml::events::Event>::borrow Line | Count | Source | 1748 | 14.5M | pub fn borrow(&self) -> Event<'_> { | 1749 | 14.5M | match self { | 1750 | 11.3M | Event::Start(e) => Event::Start(e.borrow()), | 1751 | 2.24M | Event::End(e) => Event::End(e.borrow()), | 1752 | 0 | Event::Empty(e) => Event::Empty(e.borrow()), | 1753 | 440k | Event::Text(e) => Event::Text(e.borrow()), | 1754 | 2.97k | Event::Comment(e) => Event::Comment(e.borrow()), | 1755 | 125k | Event::CData(e) => Event::CData(e.borrow()), | 1756 | 29.1k | Event::Decl(e) => Event::Decl(e.borrow()), | 1757 | 7.19k | Event::PI(e) => Event::PI(e.borrow()), | 1758 | 3.21k | Event::DocType(e) => Event::DocType(e.borrow()), | 1759 | 345k | Event::GeneralRef(e) => Event::GeneralRef(e.borrow()), | 1760 | 15.8k | Event::Eof => Event::Eof, | 1761 | | } | 1762 | 14.5M | } |
|
1763 | | } |
1764 | | |
1765 | | impl<'a> Deref for Event<'a> { |
1766 | | type Target = [u8]; |
1767 | | |
1768 | 0 | fn deref(&self) -> &[u8] { |
1769 | 0 | match *self { |
1770 | 0 | Event::Start(ref e) | Event::Empty(ref e) => e, |
1771 | 0 | Event::End(ref e) => e, |
1772 | 0 | Event::Text(ref e) => e, |
1773 | 0 | Event::Decl(ref e) => e, |
1774 | 0 | Event::PI(ref e) => e, |
1775 | 0 | Event::CData(ref e) => e, |
1776 | 0 | Event::Comment(ref e) => e, |
1777 | 0 | Event::DocType(ref e) => e, |
1778 | 0 | Event::GeneralRef(ref e) => e, |
1779 | 0 | Event::Eof => &[], |
1780 | | } |
1781 | 0 | } |
1782 | | } |
1783 | | |
1784 | | impl<'a> AsRef<Event<'a>> for Event<'a> { |
1785 | 7.28M | fn as_ref(&self) -> &Event<'a> { |
1786 | 7.28M | self |
1787 | 7.28M | } |
1788 | | } |
1789 | | |
1790 | | //////////////////////////////////////////////////////////////////////////////////////////////////// |
1791 | | |
1792 | | #[inline] |
1793 | 45.1k | fn str_cow_to_bytes<'a, C: Into<Cow<'a, str>>>(content: C) -> Cow<'a, [u8]> { |
1794 | 45.1k | match content.into() { |
1795 | 39.8k | Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()), |
1796 | 5.38k | Cow::Owned(s) => Cow::Owned(s.into_bytes()), |
1797 | | } |
1798 | 45.1k | } quick_xml::events::str_cow_to_bytes::<&alloc::string::String> Line | Count | Source | 1793 | 13.4k | fn str_cow_to_bytes<'a, C: Into<Cow<'a, str>>>(content: C) -> Cow<'a, [u8]> { | 1794 | 13.4k | match content.into() { | 1795 | 13.4k | Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()), | 1796 | 0 | Cow::Owned(s) => Cow::Owned(s.into_bytes()), | 1797 | | } | 1798 | 13.4k | } |
quick_xml::events::str_cow_to_bytes::<alloc::borrow::Cow<str>> Line | Count | Source | 1793 | 4.41k | fn str_cow_to_bytes<'a, C: Into<Cow<'a, str>>>(content: C) -> Cow<'a, [u8]> { | 1794 | 4.41k | match content.into() { | 1795 | 4.41k | Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()), | 1796 | 0 | Cow::Owned(s) => Cow::Owned(s.into_bytes()), | 1797 | | } | 1798 | 4.41k | } |
quick_xml::events::str_cow_to_bytes::<alloc::string::String> Line | Count | Source | 1793 | 5.38k | fn str_cow_to_bytes<'a, C: Into<Cow<'a, str>>>(content: C) -> Cow<'a, [u8]> { | 1794 | 5.38k | match content.into() { | 1795 | 0 | Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()), | 1796 | 5.38k | Cow::Owned(s) => Cow::Owned(s.into_bytes()), | 1797 | | } | 1798 | 5.38k | } |
quick_xml::events::str_cow_to_bytes::<&str> Line | Count | Source | 1793 | 21.9k | fn str_cow_to_bytes<'a, C: Into<Cow<'a, str>>>(content: C) -> Cow<'a, [u8]> { | 1794 | 21.9k | match content.into() { | 1795 | 21.9k | Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()), | 1796 | 0 | Cow::Owned(s) => Cow::Owned(s.into_bytes()), | 1797 | | } | 1798 | 21.9k | } |
|
1799 | | |
1800 | 0 | fn trim_cow<'a, F>(value: Cow<'a, [u8]>, trim: F) -> Cow<'a, [u8]> |
1801 | 0 | where |
1802 | 0 | F: FnOnce(&[u8]) -> &[u8], |
1803 | | { |
1804 | 0 | match value { |
1805 | 0 | Cow::Borrowed(bytes) => Cow::Borrowed(trim(bytes)), |
1806 | 0 | Cow::Owned(mut bytes) => { |
1807 | 0 | let trimmed = trim(&bytes); |
1808 | 0 | if trimmed.len() != bytes.len() { |
1809 | 0 | bytes = trimmed.to_vec(); |
1810 | 0 | } |
1811 | 0 | Cow::Owned(bytes) |
1812 | | } |
1813 | | } |
1814 | 0 | } Unexecuted instantiation: quick_xml::events::trim_cow::<quick_xml::utils::trim_xml_end> Unexecuted instantiation: quick_xml::events::trim_cow::<quick_xml::utils::trim_xml_start> |
1815 | | |
1816 | | #[cfg(test)] |
1817 | | mod test { |
1818 | | use super::*; |
1819 | | use pretty_assertions::assert_eq; |
1820 | | |
1821 | | #[test] |
1822 | | fn bytestart_create() { |
1823 | | let b = BytesStart::new("test"); |
1824 | | assert_eq!(b.len(), 4); |
1825 | | assert_eq!(b.name(), QName(b"test")); |
1826 | | } |
1827 | | |
1828 | | #[test] |
1829 | | fn bytestart_set_name() { |
1830 | | let mut b = BytesStart::new("test"); |
1831 | | assert_eq!(b.len(), 4); |
1832 | | assert_eq!(b.name(), QName(b"test")); |
1833 | | assert_eq!(b.attributes_raw(), b""); |
1834 | | b.push_attribute(("x", "a")); |
1835 | | assert_eq!(b.len(), 10); |
1836 | | assert_eq!(b.attributes_raw(), b" x=\"a\""); |
1837 | | b.set_name(b"g"); |
1838 | | assert_eq!(b.len(), 7); |
1839 | | assert_eq!(b.name(), QName(b"g")); |
1840 | | } |
1841 | | |
1842 | | #[test] |
1843 | | fn bytestart_clear_attributes() { |
1844 | | let mut b = BytesStart::new("test"); |
1845 | | b.push_attribute(("x", "y\"z")); |
1846 | | b.push_attribute(("x", "y\"z")); |
1847 | | b.clear_attributes(); |
1848 | | assert!(b.attributes().next().is_none()); |
1849 | | assert_eq!(b.len(), 4); |
1850 | | assert_eq!(b.name(), QName(b"test")); |
1851 | | } |
1852 | | } |