fn serialize_bytes(self, _value: &[u8]) -> Result<Self::Ok, Self::Error> { //TODO: customization point - allow user to decide how to encode bytes
Err(Self::Error::Unsupported( "`serialize_bytes` not supported yet".into(),
))
}
mod content; mod element; pub(crate) mod key; pub(crate) mod simple_type; mod text;
useself::content::ContentSerializer; useself::element::{ElementSerializer, Map, Struct, Tuple}; usecrate::de::TEXT_KEY; usecrate::writer::{Indentation, ToFmtWrite}; use serde::ser::{self, Serialize}; use serde::serde_if_integer128; use std::fmt::Write; use std::str::from_utf8;
/// Defines which characters would be escaped in [`Text`] events and attribute /// values. /// /// [`Text`]: crate::events::Event::Text #[derive(Debug, Clone, Copy, PartialEq, Eq)] pubenum QuoteLevel { /// Performs escaping, escape all characters that could have special meaning /// in the XML. This mode is compatible with SGML specification. /// /// Characters that will be replaced: /// /// Original | Replacement /// ---------|------------ /// `<` | `<` /// `>` | `>` /// `&` | `&` /// `"` | `"` /// `'` | `'`
Full, /// Performs escaping that is compatible with SGML specification. /// /// This level adds escaping of `>` to the `Minimal` level, which is [required] /// for compatibility with SGML. /// /// Characters that will be replaced: /// /// Original | Replacement /// ---------|------------ /// `<` | `<` /// `>` | `>` /// `&` | `&` /// /// [required]: https://www.w3.org/TR/xml11/#syntax
Partial, /// Performs the minimal possible escaping, escape only strictly necessary /// characters. /// /// Characters that will be replaced: /// /// Original | Replacement /// ---------|------------ /// `<` | `<` /// `&` | `&`
Minimal,
}
/// Classification of the type written by the serializer. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pubenum WriteResult { /// Text with insignificant spaces was written, for example a number. Adding indent to the /// serialized data does not change meaning of the data.
Text, /// The XML tag was written. Adding indent to the serialized data does not change meaning of the data.
Element, /// Nothing was written (i. e. serialized type not represented in XML a all). Adding indent to the /// serialized data does not change meaning of the data. This is returned for units, unit structs /// and unit variants.
Nothing, /// Text with significant spaces was written, for example a string. Adding indent to the /// serialized data may change meaning of the data.
SensitiveText, /// `None` was serialized and nothing was written. `None` does not represented in XML, /// but adding indent after it may change meaning of the data.
SensitiveNothing,
}
impl WriteResult { /// Returns `true` if indent should be written after the object (if configured) and `false` otherwise. #[inline] pubfn allow_indent(&self) -> bool {
matches!(self, Self::Element | Self::Nothing)
}
/// Returns `true` if self is `Text` or `SensitiveText`. #[inline] pubfn is_text(&self) -> bool {
matches!(self, Self::Text | Self::SensitiveText)
}
}
/// Almost all characters can form a name. Citation from <https://www.w3.org/TR/xml11/#sec-xml11>: /// /// > The overall philosophy of names has changed since XML 1.0. Whereas XML 1.0 /// > provided a rigid definition of names, wherein everything that was not permitted /// > was forbidden, XML 1.1 names are designed so that everything that is not /// > forbidden (for a specific reason) is permitted. Since Unicode will continue /// > to grow past version 4.0, further changes to XML can be avoided by allowing /// > almost any character, including those not yet assigned, in names. /// /// <https://www.w3.org/TR/xml11/#NT-NameStartChar> constfn is_xml11_name_start_char(ch: char) -> bool { match ch { ':'
| 'A'..='Z'
| '_'
| 'a'..='z'
| '\u{00C0}'..='\u{00D6}'
| '\u{00D8}'..='\u{00F6}'
| '\u{00F8}'..='\u{02FF}'
| '\u{0370}'..='\u{037D}'
| '\u{037F}'..='\u{1FFF}'
| '\u{200C}'..='\u{200D}'
| '\u{2070}'..='\u{218F}'
| '\u{2C00}'..='\u{2FEF}'
| '\u{3001}'..='\u{D7FF}'
| '\u{F900}'..='\u{FDCF}'
| '\u{FDF0}'..='\u{FFFD}'
| '\u{10000}'..='\u{EFFFF}' => true,
_ => false,
}
} /// <https://www.w3.org/TR/xml11/#NT-NameChar> constfn is_xml11_name_char(ch: char) -> bool { match ch { '-' | '.' | '0'..='9' | '\u{00B7}' | '\u{0300}'..='\u{036F}' | '\u{203F}'..='\u{2040}' => { true
}
_ => is_xml11_name_start_char(ch),
}
}
/// Helper struct to self-defense from errors #[derive(Clone, Copy, Debug, PartialEq)] pub(self) struct XmlName<'n>(&'n str);
impl<'n> XmlName<'n> { /// Checks correctness of the XML name according to [XML 1.1 specification] /// /// [XML 1.1 specification]: https://www.w3.org/TR/xml11/#NT-Name pubfn try_from(name: &'n str) -> Result<XmlName<'n>, SeError> { //TODO: Customization point: allow user to decide if he want to reject or encode the name match name.chars().next() {
Some(ch) if !is_xml11_name_start_char(ch) => Err(SeError::Unsupported(
format!("character `{ch}` is not allowed at the start of an XML name `{name}`")
.into(),
)),
_ => match name.matches(|ch| !is_xml11_name_char(ch)).next() {
Some(s) => Err(SeError::Unsupported(
format!("character `{s}` is not allowed in an XML name `{name}`").into(),
)),
None => Ok(XmlName(name)),
},
}
}
}
pub(crate) enum Indent<'i> { /// No indent should be written before the element
None, /// The specified indent should be written. The type owns the buffer with indent
Owned(Indentation), /// The specified indent should be written. The type borrows buffer with indent /// from its owner
Borrow(&'i mut Indentation),
}
/// A Serializer. /// /// Returns the classification of the last written type. pubstruct Serializer<'w, 'r, W: Write> {
ser: ContentSerializer<'w, 'r, W>, /// Name of the root tag. If not specified, deduced from the structure name
root_tag: Option<XmlName<'r>>,
}
impl<'w, 'r, W: Write> Serializer<'w, 'r, W> { /// Creates a new `Serializer` that uses struct name as a root tag name. /// /// Note, that attempt to serialize a non-struct (including unit structs /// and newtype structs) will end up to an error. Use `with_root` to create /// serializer with explicitly defined root element name pubfn new(writer: &'w mut W) -> Self { Self {
ser: ContentSerializer {
writer,
level: QuoteLevel::Partial,
indent: Indent::None,
write_indent: false,
allow_primitive: true,
expand_empty_elements: false,
},
root_tag: None,
}
}
/// Creates a new `Serializer` that uses specified root tag name. `name` should /// be valid [XML name], otherwise error is returned. /// /// # Examples /// /// When serializing a primitive type, only its representation will be written: /// /// ``` /// # use pretty_assertions::assert_eq; /// # use serde::Serialize; /// # use quick_xml::se::Serializer; /// /// let mut buffer = String::new(); /// let ser = Serializer::with_root(&mut buffer, Some("root")).unwrap(); /// /// "node".serialize(ser).unwrap(); /// assert_eq!(buffer, "<root>node</root>"); /// ``` /// /// When serializing a struct, newtype struct, unit struct or tuple `root_tag` /// is used as tag name of root(s) element(s): /// /// ``` /// # use pretty_assertions::assert_eq; /// # use serde::Serialize; /// # use quick_xml::se::Serializer; /// /// #[derive(Debug, PartialEq, Serialize)] /// struct Struct { /// question: String, /// answer: u32, /// } /// /// let mut buffer = String::new(); /// let ser = Serializer::with_root(&mut buffer, Some("root")).unwrap(); /// /// let data = Struct { /// question: "The Ultimate Question of Life, the Universe, and Everything".into(), /// answer: 42, /// }; /// /// data.serialize(ser).unwrap(); /// assert_eq!( /// buffer, /// "<root>\ /// <question>The Ultimate Question of Life, the Universe, and Everything</question>\ /// <answer>42</answer>\ /// </root>" /// ); /// ``` /// /// [XML name]: https://www.w3.org/TR/xml11/#NT-Name pubfn with_root(writer: &'w mut W, root_tag: Option<&'r str>) -> Result<Self, SeError> {
Ok(Self {
ser: ContentSerializer {
writer,
level: QuoteLevel::Partial,
indent: Indent::None,
write_indent: false,
allow_primitive: true,
expand_empty_elements: false,
},
root_tag: root_tag.map(|tag| XmlName::try_from(tag)).transpose()?,
})
}
/// Enable or disable expansion of empty elements. Defaults to `false`. /// /// # Examples /// /// ``` /// # use pretty_assertions::assert_eq; /// # use serde::Serialize; /// # use quick_xml::se::Serializer; /// /// #[derive(Debug, PartialEq, Serialize)] /// struct Struct { /// question: Option<String>, /// } /// /// let mut buffer = String::new(); /// let mut ser = Serializer::new(&mut buffer); /// ser.expand_empty_elements(true); /// /// let data = Struct { /// question: None, /// }; /// /// data.serialize(ser).unwrap(); /// assert_eq!( /// buffer, /// "<Struct><question></question></Struct>" /// ); /// ``` pubfn expand_empty_elements(&mutself, expand: bool) -> &e='color:red'>mutSelf { self.ser.expand_empty_elements = expand; self
}
/// Configure indent for a serializer pubfn indent(&mutself, indent_char: char, indent_size: usize) -> &pan style='color:red'>mut Self { self.ser.indent = Indent::Owned(Indentation::new(indent_char as u8, indent_size)); self
}
/// Set the level of quoting used when writing texts /// /// Default: [`QuoteLevel::Minimal`] pubfn set_quote_level(&mutself, level: QuoteLevel) -> &='color:red'>mutSelf { self.ser.level = level; self
}
/// Set the indent object for a serializer pub(crate) fn set_indent(&mutself, indent: Indent<'r>) -> &mut Self { self.ser.indent = indent; self
}
/// Creates actual serializer or returns an error if root tag is not defined. /// In that case `err` contains the name of type that cannot be serialized. fn ser(self, err: &str) -> Result<ElementSerializer<'w, 'r, W>, SeError> { iflet Some(key) = self.root_tag {
Ok(ElementSerializer { ser: self.ser, key })
} else {
Err(SeError::Unsupported(
format!("cannot serialize {} without defined root tag", err).into(),
))
}
}
/// Creates actual serializer using root tag or a specified `key` if root tag /// is not defined. Returns an error if root tag is not defined and a `key` /// does not conform [XML rules](XmlName::try_from) for names. fn ser_name(self, key: &'static str) -> Result<ElementSerializer<'w, 'r, W>, SeError> {
Ok(ElementSerializer {
ser: self.ser,
key: matchself.root_tag {
Some(key) => key,
None => XmlName::try_from(key)?,
},
})
}
}
impl<'w, 'r, W: Write> ser::Serializer for Serializer<'w, 'r, W> { type Ok = WriteResult; type Error = SeError;
type SerializeSeq = ElementSerializer<'w, 'r, W>; type SerializeTuple = ElementSerializer<'w, 'r, W>; type SerializeTupleStruct = ElementSerializer<'w, 'r, W>; type SerializeTupleVariant = Tuple<'w, 'r, W>; type SerializeMap = Map<'w, 'r, W>; type SerializeStruct = Struct<'w, 'r, W>; type SerializeStructVariant = Struct<'w, 'r, W>;
fn serialize_none(self) -> Result<Self::Ok, Self::Error> { // Do not write indent after `Option` field with `None` value, because // this can be `Option<String>`. Unfortunately, we do not known what the // type the option contains, so have no chance to adapt our behavior to it. // The safe variant is not to write indent
Ok(WriteResult::SensitiveNothing)
}
fn serialize_unit_variant( self,
name: &'static str,
_variant_index: u32,
variant: &'static str,
) -> Result<Self::Ok, Self::Error> { if variant == TEXT_KEY { // We should write some text but we don't known what text to write
Err(SeError::Unsupported(
format!( "cannot serialize enum unit variant `{}::$text` as text content value",
name
)
.into(),
))
} else { let name = XmlName::try_from(variant)?; self.ser.write_empty(name)
}
}
fn serialize_newtype_variant<T: ?Sized + Serialize>( self,
_name: &'static str,
_variant_index: u32,
variant: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error> { if variant == TEXT_KEY {
value.serialize(self.ser.into_simple_type_serializer()?)?; // Do not write indent after `$text` variant because it may be interpreted as // part of content when deserialize
Ok(WriteResult::SensitiveText)
} else { let ser = ElementSerializer {
ser: self.ser,
key: XmlName::try_from(variant)?,
};
value.serialize(ser)
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.