summaryrefslogtreecommitdiffstats
path: root/third_party/rust/xml-rs/src/name.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--third_party/rust/xml-rs/src/name.rs301
1 files changed, 301 insertions, 0 deletions
diff --git a/third_party/rust/xml-rs/src/name.rs b/third_party/rust/xml-rs/src/name.rs
new file mode 100644
index 0000000000..a20eae2f10
--- /dev/null
+++ b/third_party/rust/xml-rs/src/name.rs
@@ -0,0 +1,301 @@
+//! Contains XML qualified names manipulation types and functions.
+//!
+
+use std::fmt;
+use std::str::FromStr;
+
+use namespace::NS_NO_PREFIX;
+
+/// Represents a qualified XML name.
+///
+/// A qualified name always consists at least of a local name. It can optionally contain
+/// a prefix; when reading an XML document, if it contains a prefix, it must also contain a
+/// namespace URI, but this is not enforced statically; see below. The name can contain a
+/// namespace without a prefix; in that case a default, empty prefix is assumed.
+///
+/// When writing XML documents, it is possible to omit the namespace URI, leaving only
+/// the prefix. In this case the writer will check that the specifed prefix is bound to some
+/// URI in the current namespace context. If both prefix and namespace URI are specified,
+/// it is checked that the current namespace context contains this exact correspondence
+/// between prefix and namespace URI.
+///
+/// # Prefixes and URIs
+///
+/// A qualified name with a prefix must always contain a proper namespace URI --- names with
+/// a prefix but without a namespace associated with that prefix are meaningless. However,
+/// it is impossible to obtain proper namespace URI by a prefix without a context, and such
+/// context is only available when parsing a document (or it can be constructed manually
+/// when writing a document). Tying a name to a context statically seems impractical. This
+/// may change in future, though.
+///
+/// # Conversions
+///
+/// `Name` implements some `From` instances for conversion from strings and tuples. For example:
+///
+/// ```rust
+/// # use xml::name::Name;
+/// let n1: Name = "p:some-name".into();
+/// let n2: Name = ("p", "some-name").into();
+///
+/// assert_eq!(n1, n2);
+/// assert_eq!(n1.local_name, "some-name");
+/// assert_eq!(n1.prefix, Some("p"));
+/// assert!(n1.namespace.is_none());
+/// ```
+///
+/// This is added to support easy specification of XML elements when writing XML documents.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub struct Name<'a> {
+ /// A local name, e.g. `string` in `xsi:string`.
+ pub local_name: &'a str,
+
+ /// A namespace URI, e.g. `http://www.w3.org/2000/xmlns/`.
+ pub namespace: Option<&'a str>,
+
+ /// A name prefix, e.g. `xsi` in `xsi:string`.
+ pub prefix: Option<&'a str>
+}
+
+impl<'a> From<&'a str> for Name<'a> {
+ fn from(s: &'a str) -> Name<'a> {
+ let mut parts = s.splitn(2, ":").fuse();
+ match (parts.next(), parts.next()) {
+ (Some(name), None) => Name::local(name),
+ (Some(prefix), Some(name)) => Name::prefixed(name, prefix),
+ _ => unreachable!()
+ }
+ }
+}
+
+impl<'a> From<(&'a str, &'a str)> for Name<'a> {
+ fn from((prefix, name): (&'a str, &'a str)) -> Name<'a> {
+ Name::prefixed(name, prefix)
+ }
+}
+
+impl<'a> fmt::Display for Name<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if let Some(namespace) = self.namespace {
+ write!(f, "{{{}}}", namespace)?;
+ }
+
+ if let Some(prefix) = self.prefix {
+ write!(f, "{}:", prefix)?;
+ }
+
+ write!(f, "{}", self.local_name)
+ }
+}
+
+impl<'a> Name<'a> {
+ /// Returns an owned variant of the qualified name.
+ pub fn to_owned(&self) -> OwnedName {
+ OwnedName {
+ local_name: self.local_name.into(),
+ namespace: self.namespace.map(|s| s.into()),
+ prefix: self.prefix.map(|s| s.into())
+ }
+ }
+
+ /// Returns a new `Name` instance representing plain local name.
+ #[inline]
+ pub fn local(local_name: &str) -> Name {
+ Name {
+ local_name,
+ prefix: None,
+ namespace: None
+ }
+ }
+
+ /// Returns a new `Name` instance with the given local name and prefix.
+ #[inline]
+ pub fn prefixed(local_name: &'a str, prefix: &'a str) -> Name<'a> {
+ Name {
+ local_name,
+ namespace: None,
+ prefix: Some(prefix)
+ }
+ }
+
+ /// Returns a new `Name` instance representing a qualified name with or without a prefix and
+ /// with a namespace URI.
+ #[inline]
+ pub fn qualified(local_name: &'a str, namespace: &'a str, prefix: Option<&'a str>) -> Name<'a> {
+ Name {
+ local_name,
+ namespace: Some(namespace),
+ prefix,
+ }
+ }
+
+ /// Returns a correct XML representation of this local name and prefix.
+ ///
+ /// This method is different from the autoimplemented `to_string()` because it does not
+ /// include namespace URI in the result.
+ pub fn to_repr(&self) -> String {
+ self.repr_display().to_string()
+ }
+
+ /// Returns a structure which can be displayed with `std::fmt` machinery to obtain this
+ /// local name and prefix.
+ ///
+ /// This method is needed for efficiency purposes in order not to create unnecessary
+ /// allocations.
+ #[inline]
+ pub fn repr_display(&self) -> ReprDisplay {
+ ReprDisplay(self)
+ }
+
+ /// Returns either a prefix of this name or `namespace::NS_NO_PREFIX` constant.
+ #[inline]
+ pub fn prefix_repr(&self) -> &str {
+ self.prefix.unwrap_or(NS_NO_PREFIX)
+ }
+}
+
+/// A wrapper around `Name` whose `Display` implementation prints the wrapped name as it is
+/// displayed in an XML document.
+pub struct ReprDisplay<'a, 'b:'a>(&'a Name<'b>);
+
+impl<'a, 'b:'a> fmt::Display for ReprDisplay<'a, 'b> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self.0.prefix {
+ Some(prefix) => write!(f, "{}:{}", prefix, self.0.local_name),
+ None => write!(f, "{}", self.0.local_name)
+ }
+ }
+}
+
+/// An owned variant of `Name`.
+///
+/// Everything about `Name` applies to this structure as well.
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub struct OwnedName {
+ /// A local name, e.g. `string` in `xsi:string`.
+ pub local_name: String,
+
+ /// A namespace URI, e.g. `http://www.w3.org/2000/xmlns/`.
+ pub namespace: Option<String>,
+
+ /// A name prefix, e.g. `xsi` in `xsi:string`.
+ pub prefix: Option<String>,
+}
+
+impl fmt::Display for OwnedName {
+ #[inline]
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.borrow(), f)
+ }
+}
+
+impl OwnedName {
+ /// Constructs a borrowed `Name` based on this owned name.
+ pub fn borrow(&self) -> Name {
+ Name {
+ local_name: &*self.local_name,
+ namespace: self.namespace.as_ref().map(|s| &**s),
+ prefix: self.prefix.as_ref().map(|s| &**s),
+ }
+ }
+
+ /// Returns a new `OwnedName` instance representing a plain local name.
+ #[inline]
+ pub fn local<S>(local_name: S) -> OwnedName where S: Into<String> {
+ OwnedName {
+ local_name: local_name.into(),
+ namespace: None,
+ prefix: None,
+ }
+ }
+
+ /// Returns a new `OwnedName` instance representing a qualified name with or without
+ /// a prefix and with a namespace URI.
+ #[inline]
+ pub fn qualified<S1, S2, S3>(local_name: S1, namespace: S2, prefix: Option<S3>) -> OwnedName
+ where S1: Into<String>, S2: Into<String>, S3: Into<String>
+ {
+ OwnedName {
+ local_name: local_name.into(),
+ namespace: Some(namespace.into()),
+ prefix: prefix.map(|v| v.into())
+ }
+ }
+
+ /// Returns an optional prefix by reference, equivalent to `self.borrow().prefix`
+ /// but avoids extra work.
+ #[inline]
+ pub fn prefix_ref(&self) -> Option<&str> {
+ self.prefix.as_ref().map(|s| &**s)
+ }
+
+ /// Returns an optional namespace by reference, equivalen to `self.borrow().namespace`
+ /// but avoids extra work.
+ #[inline]
+ pub fn namespace_ref(&self) -> Option<&str> {
+ self.namespace.as_ref().map(|s| &**s)
+ }
+}
+
+impl<'a> From<Name<'a>> for OwnedName {
+ #[inline]
+ fn from(n: Name<'a>) -> OwnedName {
+ n.to_owned()
+ }
+}
+
+impl FromStr for OwnedName {
+ type Err = ();
+
+ /// Parses the given string slice into a qualified name.
+ ///
+ /// This function, when finishes sucessfully, always return a qualified
+ /// name without a namespace (`name.namespace == None`). It should be filled later
+ /// using proper `NamespaceStack`.
+ ///
+ /// It is supposed that all characters in the argument string are correct
+ /// as defined by the XML specification. No additional checks except a check
+ /// for emptiness are done.
+ fn from_str(s: &str) -> Result<OwnedName, ()> {
+ let mut it = s.split(':');
+
+ let r = match (it.next(), it.next(), it.next()) {
+ (Some(prefix), Some(local_name), None) if !prefix.is_empty() &&
+ !local_name.is_empty() =>
+ Some((local_name.into(), Some(prefix.into()))),
+ (Some(local_name), None, None) if !local_name.is_empty() =>
+ Some((local_name.into(), None)),
+ (_, _, _) => None
+ };
+ r.map(|(local_name, prefix)| OwnedName {
+ local_name,
+ namespace: None,
+ prefix
+ }).ok_or(())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::OwnedName;
+
+ #[test]
+ fn test_owned_name_from_str() {
+ assert_eq!("prefix:name".parse(), Ok(OwnedName {
+ local_name: "name".into(),
+ namespace: None,
+ prefix: Some("prefix".into())
+ }));
+
+ assert_eq!("name".parse(), Ok(OwnedName {
+ local_name: "name".into(),
+ namespace: None,
+ prefix: None
+ }));
+
+ assert_eq!("".parse(), Err::<OwnedName, ()>(()));
+ assert_eq!(":".parse(), Err::<OwnedName, ()>(()));
+ assert_eq!(":a".parse(), Err::<OwnedName, ()>(()));
+ assert_eq!("a:".parse(), Err::<OwnedName, ()>(()));
+ assert_eq!("a:b:c".parse(), Err::<OwnedName, ()>(()));
+ }
+}