2020-02-14 23:40:38 +00:00
|
|
|
// Copyright (c) 2020 lumi <lumi@pew.im>
|
|
|
|
// Copyright (c) 2020 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
|
|
|
|
// Copyright (c) 2020 Maxime “pep” Buquet <pep@bouah.net>
|
|
|
|
//
|
|
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
|
2018-12-23 14:59:13 +00:00
|
|
|
//! Provides the `Node` struct, which represents a node in the DOM.
|
|
|
|
|
2022-04-23 13:29:03 +00:00
|
|
|
use crate::element::{Element, ElementBuilder, ItemWriter};
|
2019-09-13 01:07:02 +00:00
|
|
|
use crate::error::Result;
|
|
|
|
|
2022-04-23 13:29:03 +00:00
|
|
|
use rxml::writer::Item;
|
2018-12-23 14:59:13 +00:00
|
|
|
|
2022-04-23 13:29:03 +00:00
|
|
|
use std::convert::TryInto;
|
|
|
|
use std::io::Write;
|
2018-12-23 14:59:13 +00:00
|
|
|
|
|
|
|
/// A node in an element tree.
|
2019-11-29 13:33:17 +00:00
|
|
|
#[derive(Clone, Debug, Eq)]
|
2018-12-23 14:59:13 +00:00
|
|
|
pub enum Node {
|
|
|
|
/// An `Element`.
|
|
|
|
Element(Element),
|
|
|
|
/// A text node.
|
|
|
|
Text(String),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Node {
|
|
|
|
/// Turns this into a reference to an `Element` if this is an element node.
|
|
|
|
/// Else this returns `None`.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use minidom::Node;
|
|
|
|
///
|
minidom: forcing a namespace on Element. Stop requiring prefixes.
Below is what I think I did.
A few changes:
- Change prefixes to be something less important in the API.
- Rework the Element struct to force a namespace. In XMPP everything is
namespaced.
- Remove parent ref on what was previously NamespaceSet and is now
Prefixes.
More specifically this means `Element::new` has changed to require
`Element`'s new new properties as parameters. `Element::builder` and
`Element::bare` now require a namespace unconditionally.
`Element::prefix` has been removed.
This new API is based on the fact that prefixes are non-essential
(really just an implementation detail) and shouldn't be visible to the
user. It is possible nonetheless to set custom prefixes for
compatibility reasons with `ElementBuilder::prefix`. **A prefix is
firstly mapped to a namespace, and then attached to an element**, there
cannot be a prefix without a namespace.
Prefix inheritance is used if possible but for the case with no
prefix ("xmlns") to be reused, we only check custom prefixes declared on
the tag itself and not ascendants. If it's already used then we generate
prefixes (ns0, ns1, ..) checking on what has been declared on all
ascendants (plus of course those already set on the current tag).
Example API:
```rust
let mut elem = ElementBuilder("stream", "http://etherx.jabber.org/streams")
.prefix(Some(String::from("stream")), "http://etherx.jabber.org/streams)
.prefix(None, "jabber:client")
.attr(..)
.build();
assert_eq!(elem.ns(), String::from("http://etherx.jabber.org/streams"));
```
See also the few tests added in src/tests.
TODO: Fix inconsistencies wrt. "prefix:name" format provided as a name
when creating an Element with `Element::new` or `Element::bare`.
`Element::builder` already handles this as it should, splitting name and
prefix.
TODO: Change `Element::name` method to `Element::local_name` to make it
more explicit.
Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
2020-03-27 12:45:22 +00:00
|
|
|
/// let elm = Node::Element("<meow xmlns=\"ns1\"/>".parse().unwrap());
|
2018-12-23 14:59:13 +00:00
|
|
|
/// let txt = Node::Text("meow".to_owned());
|
|
|
|
///
|
|
|
|
/// assert_eq!(elm.as_element().unwrap().name(), "meow");
|
|
|
|
/// assert_eq!(txt.as_element(), None);
|
|
|
|
/// ```
|
|
|
|
pub fn as_element(&self) -> Option<&Element> {
|
|
|
|
match *self {
|
|
|
|
Node::Element(ref e) => Some(e),
|
|
|
|
Node::Text(_) => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Turns this into a mutable reference of an `Element` if this is an element node.
|
|
|
|
/// Else this returns `None`.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use minidom::Node;
|
|
|
|
///
|
minidom: forcing a namespace on Element. Stop requiring prefixes.
Below is what I think I did.
A few changes:
- Change prefixes to be something less important in the API.
- Rework the Element struct to force a namespace. In XMPP everything is
namespaced.
- Remove parent ref on what was previously NamespaceSet and is now
Prefixes.
More specifically this means `Element::new` has changed to require
`Element`'s new new properties as parameters. `Element::builder` and
`Element::bare` now require a namespace unconditionally.
`Element::prefix` has been removed.
This new API is based on the fact that prefixes are non-essential
(really just an implementation detail) and shouldn't be visible to the
user. It is possible nonetheless to set custom prefixes for
compatibility reasons with `ElementBuilder::prefix`. **A prefix is
firstly mapped to a namespace, and then attached to an element**, there
cannot be a prefix without a namespace.
Prefix inheritance is used if possible but for the case with no
prefix ("xmlns") to be reused, we only check custom prefixes declared on
the tag itself and not ascendants. If it's already used then we generate
prefixes (ns0, ns1, ..) checking on what has been declared on all
ascendants (plus of course those already set on the current tag).
Example API:
```rust
let mut elem = ElementBuilder("stream", "http://etherx.jabber.org/streams")
.prefix(Some(String::from("stream")), "http://etherx.jabber.org/streams)
.prefix(None, "jabber:client")
.attr(..)
.build();
assert_eq!(elem.ns(), String::from("http://etherx.jabber.org/streams"));
```
See also the few tests added in src/tests.
TODO: Fix inconsistencies wrt. "prefix:name" format provided as a name
when creating an Element with `Element::new` or `Element::bare`.
`Element::builder` already handles this as it should, splitting name and
prefix.
TODO: Change `Element::name` method to `Element::local_name` to make it
more explicit.
Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
2020-03-27 12:45:22 +00:00
|
|
|
/// let mut elm = Node::Element("<meow xmlns=\"ns1\"/>".parse().unwrap());
|
2018-12-23 14:59:13 +00:00
|
|
|
/// let mut txt = Node::Text("meow".to_owned());
|
|
|
|
///
|
|
|
|
/// assert_eq!(elm.as_element_mut().unwrap().name(), "meow");
|
|
|
|
/// assert_eq!(txt.as_element_mut(), None);
|
|
|
|
/// ```
|
|
|
|
pub fn as_element_mut(&mut self) -> Option<&mut Element> {
|
|
|
|
match *self {
|
|
|
|
Node::Element(ref mut e) => Some(e),
|
|
|
|
Node::Text(_) => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Turns this into an `Element`, consuming self, if this is an element node.
|
|
|
|
/// Else this returns `None`.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use minidom::Node;
|
|
|
|
///
|
minidom: forcing a namespace on Element. Stop requiring prefixes.
Below is what I think I did.
A few changes:
- Change prefixes to be something less important in the API.
- Rework the Element struct to force a namespace. In XMPP everything is
namespaced.
- Remove parent ref on what was previously NamespaceSet and is now
Prefixes.
More specifically this means `Element::new` has changed to require
`Element`'s new new properties as parameters. `Element::builder` and
`Element::bare` now require a namespace unconditionally.
`Element::prefix` has been removed.
This new API is based on the fact that prefixes are non-essential
(really just an implementation detail) and shouldn't be visible to the
user. It is possible nonetheless to set custom prefixes for
compatibility reasons with `ElementBuilder::prefix`. **A prefix is
firstly mapped to a namespace, and then attached to an element**, there
cannot be a prefix without a namespace.
Prefix inheritance is used if possible but for the case with no
prefix ("xmlns") to be reused, we only check custom prefixes declared on
the tag itself and not ascendants. If it's already used then we generate
prefixes (ns0, ns1, ..) checking on what has been declared on all
ascendants (plus of course those already set on the current tag).
Example API:
```rust
let mut elem = ElementBuilder("stream", "http://etherx.jabber.org/streams")
.prefix(Some(String::from("stream")), "http://etherx.jabber.org/streams)
.prefix(None, "jabber:client")
.attr(..)
.build();
assert_eq!(elem.ns(), String::from("http://etherx.jabber.org/streams"));
```
See also the few tests added in src/tests.
TODO: Fix inconsistencies wrt. "prefix:name" format provided as a name
when creating an Element with `Element::new` or `Element::bare`.
`Element::builder` already handles this as it should, splitting name and
prefix.
TODO: Change `Element::name` method to `Element::local_name` to make it
more explicit.
Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
2020-03-27 12:45:22 +00:00
|
|
|
/// let elm = Node::Element("<meow xmlns=\"ns1\"/>".parse().unwrap());
|
2018-12-23 14:59:13 +00:00
|
|
|
/// let txt = Node::Text("meow".to_owned());
|
|
|
|
///
|
|
|
|
/// assert_eq!(elm.into_element().unwrap().name(), "meow");
|
|
|
|
/// assert_eq!(txt.into_element(), None);
|
|
|
|
/// ```
|
|
|
|
pub fn into_element(self) -> Option<Element> {
|
|
|
|
match self {
|
|
|
|
Node::Element(e) => Some(e),
|
|
|
|
Node::Text(_) => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Turns this into an `&str` if this is a text node.
|
|
|
|
/// Else this returns `None`.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use minidom::Node;
|
|
|
|
///
|
minidom: forcing a namespace on Element. Stop requiring prefixes.
Below is what I think I did.
A few changes:
- Change prefixes to be something less important in the API.
- Rework the Element struct to force a namespace. In XMPP everything is
namespaced.
- Remove parent ref on what was previously NamespaceSet and is now
Prefixes.
More specifically this means `Element::new` has changed to require
`Element`'s new new properties as parameters. `Element::builder` and
`Element::bare` now require a namespace unconditionally.
`Element::prefix` has been removed.
This new API is based on the fact that prefixes are non-essential
(really just an implementation detail) and shouldn't be visible to the
user. It is possible nonetheless to set custom prefixes for
compatibility reasons with `ElementBuilder::prefix`. **A prefix is
firstly mapped to a namespace, and then attached to an element**, there
cannot be a prefix without a namespace.
Prefix inheritance is used if possible but for the case with no
prefix ("xmlns") to be reused, we only check custom prefixes declared on
the tag itself and not ascendants. If it's already used then we generate
prefixes (ns0, ns1, ..) checking on what has been declared on all
ascendants (plus of course those already set on the current tag).
Example API:
```rust
let mut elem = ElementBuilder("stream", "http://etherx.jabber.org/streams")
.prefix(Some(String::from("stream")), "http://etherx.jabber.org/streams)
.prefix(None, "jabber:client")
.attr(..)
.build();
assert_eq!(elem.ns(), String::from("http://etherx.jabber.org/streams"));
```
See also the few tests added in src/tests.
TODO: Fix inconsistencies wrt. "prefix:name" format provided as a name
when creating an Element with `Element::new` or `Element::bare`.
`Element::builder` already handles this as it should, splitting name and
prefix.
TODO: Change `Element::name` method to `Element::local_name` to make it
more explicit.
Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
2020-03-27 12:45:22 +00:00
|
|
|
/// let elm = Node::Element("<meow xmlns=\"ns1\"/>".parse().unwrap());
|
2018-12-23 14:59:13 +00:00
|
|
|
/// let txt = Node::Text("meow".to_owned());
|
|
|
|
///
|
|
|
|
/// assert_eq!(elm.as_text(), None);
|
|
|
|
/// assert_eq!(txt.as_text().unwrap(), "meow");
|
|
|
|
/// ```
|
|
|
|
pub fn as_text(&self) -> Option<&str> {
|
|
|
|
match *self {
|
|
|
|
Node::Element(_) => None,
|
|
|
|
Node::Text(ref s) => Some(s),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Turns this into an `&mut String` if this is a text node.
|
|
|
|
/// Else this returns `None`.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use minidom::Node;
|
|
|
|
///
|
minidom: forcing a namespace on Element. Stop requiring prefixes.
Below is what I think I did.
A few changes:
- Change prefixes to be something less important in the API.
- Rework the Element struct to force a namespace. In XMPP everything is
namespaced.
- Remove parent ref on what was previously NamespaceSet and is now
Prefixes.
More specifically this means `Element::new` has changed to require
`Element`'s new new properties as parameters. `Element::builder` and
`Element::bare` now require a namespace unconditionally.
`Element::prefix` has been removed.
This new API is based on the fact that prefixes are non-essential
(really just an implementation detail) and shouldn't be visible to the
user. It is possible nonetheless to set custom prefixes for
compatibility reasons with `ElementBuilder::prefix`. **A prefix is
firstly mapped to a namespace, and then attached to an element**, there
cannot be a prefix without a namespace.
Prefix inheritance is used if possible but for the case with no
prefix ("xmlns") to be reused, we only check custom prefixes declared on
the tag itself and not ascendants. If it's already used then we generate
prefixes (ns0, ns1, ..) checking on what has been declared on all
ascendants (plus of course those already set on the current tag).
Example API:
```rust
let mut elem = ElementBuilder("stream", "http://etherx.jabber.org/streams")
.prefix(Some(String::from("stream")), "http://etherx.jabber.org/streams)
.prefix(None, "jabber:client")
.attr(..)
.build();
assert_eq!(elem.ns(), String::from("http://etherx.jabber.org/streams"));
```
See also the few tests added in src/tests.
TODO: Fix inconsistencies wrt. "prefix:name" format provided as a name
when creating an Element with `Element::new` or `Element::bare`.
`Element::builder` already handles this as it should, splitting name and
prefix.
TODO: Change `Element::name` method to `Element::local_name` to make it
more explicit.
Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
2020-03-27 12:45:22 +00:00
|
|
|
/// let mut elm = Node::Element("<meow xmlns=\"ns1\"/>".parse().unwrap());
|
2018-12-23 14:59:13 +00:00
|
|
|
/// let mut txt = Node::Text("meow".to_owned());
|
|
|
|
///
|
|
|
|
/// assert_eq!(elm.as_text_mut(), None);
|
|
|
|
/// {
|
|
|
|
/// let text_mut = txt.as_text_mut().unwrap();
|
|
|
|
/// assert_eq!(text_mut, "meow");
|
|
|
|
/// text_mut.push_str("zies");
|
|
|
|
/// assert_eq!(text_mut, "meowzies");
|
|
|
|
/// }
|
|
|
|
/// assert_eq!(txt.as_text().unwrap(), "meowzies");
|
|
|
|
/// ```
|
|
|
|
pub fn as_text_mut(&mut self) -> Option<&mut String> {
|
|
|
|
match *self {
|
|
|
|
Node::Element(_) => None,
|
|
|
|
Node::Text(ref mut s) => Some(s),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Turns this into an `String`, consuming self, if this is a text node.
|
|
|
|
/// Else this returns `None`.
|
|
|
|
///
|
|
|
|
/// # Examples
|
|
|
|
///
|
|
|
|
/// ```rust
|
|
|
|
/// use minidom::Node;
|
|
|
|
///
|
minidom: forcing a namespace on Element. Stop requiring prefixes.
Below is what I think I did.
A few changes:
- Change prefixes to be something less important in the API.
- Rework the Element struct to force a namespace. In XMPP everything is
namespaced.
- Remove parent ref on what was previously NamespaceSet and is now
Prefixes.
More specifically this means `Element::new` has changed to require
`Element`'s new new properties as parameters. `Element::builder` and
`Element::bare` now require a namespace unconditionally.
`Element::prefix` has been removed.
This new API is based on the fact that prefixes are non-essential
(really just an implementation detail) and shouldn't be visible to the
user. It is possible nonetheless to set custom prefixes for
compatibility reasons with `ElementBuilder::prefix`. **A prefix is
firstly mapped to a namespace, and then attached to an element**, there
cannot be a prefix without a namespace.
Prefix inheritance is used if possible but for the case with no
prefix ("xmlns") to be reused, we only check custom prefixes declared on
the tag itself and not ascendants. If it's already used then we generate
prefixes (ns0, ns1, ..) checking on what has been declared on all
ascendants (plus of course those already set on the current tag).
Example API:
```rust
let mut elem = ElementBuilder("stream", "http://etherx.jabber.org/streams")
.prefix(Some(String::from("stream")), "http://etherx.jabber.org/streams)
.prefix(None, "jabber:client")
.attr(..)
.build();
assert_eq!(elem.ns(), String::from("http://etherx.jabber.org/streams"));
```
See also the few tests added in src/tests.
TODO: Fix inconsistencies wrt. "prefix:name" format provided as a name
when creating an Element with `Element::new` or `Element::bare`.
`Element::builder` already handles this as it should, splitting name and
prefix.
TODO: Change `Element::name` method to `Element::local_name` to make it
more explicit.
Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
2020-03-27 12:45:22 +00:00
|
|
|
/// let elm = Node::Element("<meow xmlns=\"ns1\"/>".parse().unwrap());
|
2018-12-23 14:59:13 +00:00
|
|
|
/// let txt = Node::Text("meow".to_owned());
|
|
|
|
///
|
|
|
|
/// assert_eq!(elm.into_text(), None);
|
|
|
|
/// assert_eq!(txt.into_text().unwrap(), "meow");
|
|
|
|
/// ```
|
|
|
|
pub fn into_text(self) -> Option<String> {
|
|
|
|
match self {
|
|
|
|
Node::Element(_) => None,
|
|
|
|
Node::Text(s) => Some(s),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
2022-04-23 13:29:03 +00:00
|
|
|
pub(crate) fn write_to_inner<W: Write>(&self, writer: &mut ItemWriter<W>) -> Result<()> {
|
2018-12-23 14:59:13 +00:00
|
|
|
match *self {
|
2022-04-23 13:29:03 +00:00
|
|
|
Node::Element(ref elmt) => elmt.write_to_inner(writer)?,
|
2018-12-23 14:59:13 +00:00
|
|
|
Node::Text(ref s) => {
|
2022-04-23 13:29:03 +00:00
|
|
|
writer.write(Item::Text((&**s).try_into()?))?;
|
2019-10-22 23:32:41 +00:00
|
|
|
}
|
2019-02-21 20:06:23 +00:00
|
|
|
}
|
2018-12-23 14:59:13 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-03 17:49:11 +00:00
|
|
|
impl<I> From<I> for Node
|
2019-11-06 02:51:58 +00:00
|
|
|
where
|
|
|
|
I: Into<Element>,
|
2019-11-03 17:49:11 +00:00
|
|
|
{
|
|
|
|
fn from(elm: I) -> Node {
|
|
|
|
Node::Element(elm.into())
|
2018-12-23 14:59:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<String> for Node {
|
|
|
|
fn from(s: String) -> Node {
|
|
|
|
Node::Text(s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> From<&'a str> for Node {
|
|
|
|
fn from(s: &'a str) -> Node {
|
|
|
|
Node::Text(s.to_owned())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<ElementBuilder> for Node {
|
|
|
|
fn from(builder: ElementBuilder) -> Node {
|
|
|
|
Node::Element(builder.build())
|
|
|
|
}
|
|
|
|
}
|
2019-11-29 13:33:17 +00:00
|
|
|
|
|
|
|
impl PartialEq for Node {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
match (self, other) {
|
|
|
|
(&Node::Element(ref elem1), &Node::Element(ref elem2)) => elem1 == elem2,
|
|
|
|
(&Node::Text(ref text1), &Node::Text(ref text2)) => text1 == text2,
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|