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