#![allow(clippy::wrong_self_convention)]
use std::borrow::Cow;
use std::cmp::Ord;
use std::cmp::Ordering;
use std::collections::btree_map::Iter as BTreeMapIter;
use std::collections::BTreeMap;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::io;
use std::io::{Read, Write};
use std::mem;
use std::ops::Deref;
use std::rc::Rc;
use std::str::Utf8Error;
use string_cache::DefaultAtom as Atom;
mod xml;
use crate::xml::attribute::{Attribute, OwnedAttribute};
use crate::xml::common::Position as XmlPosition;
use crate::xml::common::XmlVersion;
use crate::xml::name::{Name, OwnedName};
use crate::xml::namespace::{Namespace as XmlNamespaceMap, NS_EMPTY_URI, NS_XMLNS_URI, NS_XML_URI};
use crate::xml::reader::{
Error as XmlReadError, ErrorKind as XmlReadErrorKind, EventReader, ParserConfig, XmlEvent,
};
use crate::xml::writer::{Error as XmlWriteError, EventWriter, XmlEvent as XmlWriteEvent};
use crate::xml::EmitterConfig;
enum XmlAtom<'a> {
Shared(Atom),
Borrowed(&'a str),
}
impl<'a> Deref for XmlAtom<'a> {
type Target = str;
#[inline(always)]
fn deref(&self) -> &str {
match *self {
XmlAtom::Shared(ref atom) => atom.deref(),
XmlAtom::Borrowed(s) => s,
}
}
}
impl<'a> XmlAtom<'a> {
#[inline(always)]
pub fn borrow(&self) -> &str {
self
}
}
impl<'a> fmt::Debug for XmlAtom<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self.borrow())
}
}
impl<'a> Clone for XmlAtom<'a> {
fn clone(&self) -> XmlAtom<'a> {
XmlAtom::Shared(Atom::from(self.borrow()))
}
}
impl<'a> PartialEq for XmlAtom<'a> {
fn eq(&self, other: &XmlAtom<'a>) -> bool {
self.borrow().eq(other.borrow())
}
}
impl<'a> Eq for XmlAtom<'a> {}
impl<'a> PartialOrd for XmlAtom<'a> {
fn partial_cmp(&self, other: &XmlAtom<'a>) -> Option<Ordering> {
self.borrow().partial_cmp(other.borrow())
}
}
impl<'a> Ord for XmlAtom<'a> {
fn cmp(&self, other: &XmlAtom<'a>) -> Ordering {
self.borrow().cmp(other.borrow())
}
}
pub trait AsQName<'a> {
fn as_qname(&self) -> Cow<'a, QName<'a>>;
}
impl<'a> AsQName<'a> for &'a QName<'a> {
#[inline(always)]
fn as_qname(&self) -> Cow<'a, QName<'a>> {
Cow::Borrowed(self)
}
}
impl<'a> AsQName<'a> for &'a str {
#[inline(always)]
fn as_qname(&self) -> Cow<'a, QName<'a>> {
Cow::Owned(QName::from(self))
}
}
impl<'a> AsQName<'a> for (&'a str, &'a str) {
#[inline(always)]
fn as_qname(&self) -> Cow<'a, QName<'a>> {
Cow::Owned(QName::from_ns_name(Some(self.0), self.1))
}
}
#[derive(Clone)]
pub struct QName<'a> {
ns: Option<XmlAtom<'a>>,
name: XmlAtom<'a>,
}
impl<'a> QName<'a> {
pub fn from(s: &'a str) -> QName<'a> {
let mut ns = None;
let mut name = None;
if s.starts_with('{') {
if let Some(index) = s.find('}') {
if index > 1 {
ns = Some(XmlAtom::Borrowed(&s[1..index]));
}
name = Some(XmlAtom::Borrowed(&s[index + 1..]));
}
}
QName {
ns,
name: name.unwrap_or(XmlAtom::Borrowed(s)),
}
}
pub fn from_name(name: &'a str) -> QName<'a> {
QName {
ns: None,
name: XmlAtom::Borrowed(name),
}
}
pub fn from_ns_name(ns: Option<&'a str>, name: &'a str) -> QName<'a> {
QName {
ns: ns.map(XmlAtom::Borrowed),
name: XmlAtom::Borrowed(name),
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn ns(&self) -> Option<&str> {
self.ns.as_ref().map(|x| x.borrow())
}
pub fn share(&self) -> QName<'static> {
QName {
name: XmlAtom::Shared(Atom::from(self.name.borrow())),
ns: self
.ns
.as_ref()
.map(|x| XmlAtom::Shared(Atom::from(x.borrow()))),
}
}
fn from_owned_name(name: OwnedName) -> QName<'static> {
QName {
name: XmlAtom::Shared(Atom::from(name.local_name)),
ns: match name.namespace {
Some(ns) => {
if !ns.is_empty() {
Some(XmlAtom::Shared(Atom::from(ns)))
} else {
None
}
}
_ => None,
},
}
}
}
impl<'a> PartialEq for QName<'a> {
fn eq(&self, other: &QName<'a>) -> bool {
self.name() == other.name() && self.ns() == other.ns()
}
}
impl<'a> fmt::Debug for QName<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "QName(\"{}\")", self)
}
}
impl<'a> fmt::Display for QName<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(ref ns) = self.ns {
write!(f, "{{{}}}", ns.borrow())?;
}
write!(f, "{}", self.name.borrow())
}
}
impl<'a> Eq for QName<'a> {}
impl<'a> Hash for QName<'a> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.name.hash(state);
if let Some(ref ns) = self.ns {
ns.hash(state);
}
}
}
impl<'a> PartialOrd for QName<'a> {
fn partial_cmp(&self, other: &QName<'a>) -> Option<Ordering> {
(self.name(), self.ns()).partial_cmp(&(other.name(), other.ns()))
}
}
impl<'a> Ord for QName<'a> {
fn cmp(&self, other: &QName<'a>) -> Ordering {
(self.name(), self.ns()).cmp(&(other.name(), other.ns()))
}
}
#[derive(Debug, Clone)]
struct NamespaceMap {
prefix_to_ns: BTreeMap<XmlAtom<'static>, XmlAtom<'static>>,
ns_to_prefix: BTreeMap<XmlAtom<'static>, XmlAtom<'static>>,
}
impl NamespaceMap {
pub fn new() -> NamespaceMap {
NamespaceMap {
prefix_to_ns: BTreeMap::new(),
ns_to_prefix: BTreeMap::new(),
}
}
pub fn get_prefix(&self, url: &str) -> Option<&str> {
let atom = XmlAtom::Borrowed(url);
let static_atom: &XmlAtom<'static> = unsafe { mem::transmute(&atom) };
self.ns_to_prefix.get(static_atom).map(|x| x.borrow())
}
pub fn set_prefix(&mut self, url: &str, prefix: &str) -> Result<(), Error> {
let prefix = XmlAtom::Shared(Atom::from(prefix));
if self.prefix_to_ns.contains_key(&prefix) {
return Err(Error::DuplicateNamespacePrefix);
}
let url = XmlAtom::Shared(Atom::from(url));
if let Some(old_prefix) = self.ns_to_prefix.remove(&url) {
self.prefix_to_ns.remove(&old_prefix);
}
self.ns_to_prefix.insert(url.clone(), prefix.clone());
self.prefix_to_ns.insert(prefix.clone(), url.clone());
Ok(())
}
fn generate_prefix(&self) -> XmlAtom<'static> {
let mut i = 1;
loop {
let random_prefix = format!("ns{}", i);
if !self
.prefix_to_ns
.contains_key(&XmlAtom::Borrowed(&random_prefix))
{
return XmlAtom::Shared(Atom::from(random_prefix));
}
i += 1;
}
}
pub fn register_if_missing(&mut self, url: &str, prefix: Option<&str>) -> bool {
if self.get_prefix(url).is_some() {
return false;
}
let stored_prefix = if let Some(prefix) = prefix {
let prefix = XmlAtom::Borrowed(prefix);
if self.prefix_to_ns.get(&prefix).is_some() {
self.generate_prefix()
} else {
XmlAtom::Shared(Atom::from(prefix.borrow()))
}
} else {
self.generate_prefix()
};
let url = XmlAtom::Shared(Atom::from(url));
self.prefix_to_ns.insert(stored_prefix.clone(), url.clone());
self.ns_to_prefix.insert(url, stored_prefix);
true
}
}
#[derive(Debug, Clone)]
pub struct Element {
tag: QName<'static>,
attributes: BTreeMap<QName<'static>, String>,
children: Vec<Element>,
nsmap: Option<Rc<NamespaceMap>>,
emit_nsmap: bool,
text: String,
tail: String,
}
pub struct Children<'a> {
idx: usize,
element: &'a Element,
}
pub struct ChildrenMut<'a> {
iter: ::std::slice::IterMut<'a, Element>,
}
pub struct Attrs<'a> {
iter: BTreeMapIter<'a, QName<'a>, String>,
}
pub struct FindChildren<'a> {
tag: Cow<'a, QName<'a>>,
child_iter: Children<'a>,
}
pub struct FindChildrenMut<'a> {
tag: Cow<'a, QName<'a>>,
child_iter: ChildrenMut<'a>,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
pub struct Position {
line: u64,
column: u64,
}
impl Position {
pub fn new(line: u64, column: u64) -> Position {
Position { line, column }
}
fn from_xml_position(pos: &dyn XmlPosition) -> Position {
let pos = pos.position();
Position::new(pos.row, pos.column)
}
pub fn line(&self) -> u64 {
self.line
}
pub fn column(&self) -> u64 {
self.column
}
}
impl fmt::Display for Position {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}:{}", self.line, self.column)
}
}
#[derive(Debug)]
pub enum Error {
MalformedXml {
msg: Cow<'static, str>,
pos: Position,
},
Io(io::Error),
Utf8(Utf8Error),
UnexpectedEvent {
msg: Cow<'static, str>,
pos: Position,
},
DuplicateNamespacePrefix,
}
impl Error {
pub fn position(&self) -> Option<Position> {
match self {
Error::MalformedXml { pos, .. } => Some(*pos),
Error::UnexpectedEvent { pos, .. } => Some(*pos),
_ => None,
}
}
pub fn line(&self) -> u64 {
self.position().map(|x| x.line()).unwrap_or(0)
}
pub fn column(&self) -> u64 {
self.position().map(|x| x.column()).unwrap_or(0)
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::MalformedXml { ref pos, ref msg } => {
write!(f, "Malformed XML: {} ({})", msg, pos)
}
Error::Io(ref e) => write!(f, "{}", e),
Error::Utf8(ref e) => write!(f, "{}", e),
Error::UnexpectedEvent { ref msg, .. } => write!(f, "Unexpected XML event: {}", msg),
Error::DuplicateNamespacePrefix => {
write!(f, "Encountered duplicated namespace prefix")
}
}
}
}
impl std::error::Error for Error {
fn cause(&self) -> Option<&dyn std::error::Error> {
match *self {
Error::Io(ref e) => Some(e),
Error::Utf8(ref e) => Some(e),
_ => None,
}
}
}
impl From<XmlReadError> for Error {
fn from(err: XmlReadError) -> Error {
match *err.kind() {
XmlReadErrorKind::Io(ref err) => Error::Io(io::Error::new(err.kind(), err.to_string())),
XmlReadErrorKind::Utf8(err) => Error::Utf8(err),
XmlReadErrorKind::UnexpectedEof => Error::Io(io::Error::new(
io::ErrorKind::UnexpectedEof,
"Encountered unexpected eof",
)),
XmlReadErrorKind::Syntax(ref msg) => Error::MalformedXml {
msg: msg.clone(),
pos: Position::from_xml_position(&err),
},
}
}
}
impl From<XmlWriteError> for Error {
fn from(err: XmlWriteError) -> Error {
match err {
XmlWriteError::Io(err) => Error::Io(err),
err => Err(err).unwrap(),
}
}
}
impl<'a> Iterator for Children<'a> {
type Item = &'a Element;
fn next(&mut self) -> Option<&'a Element> {
if self.idx < self.element.children.len() {
let rv = &self.element.children[self.idx];
self.idx += 1;
Some(rv)
} else {
None
}
}
}
impl<'a> Iterator for ChildrenMut<'a> {
type Item = &'a mut Element;
fn next(&mut self) -> Option<&'a mut Element> {
self.iter.next()
}
}
impl<'a> Iterator for Attrs<'a> {
type Item = (&'a QName<'a>, &'a str);
fn next(&mut self) -> Option<(&'a QName<'a>, &'a str)> {
if let Some((k, v)) = self.iter.next() {
Some((k, v.as_str()))
} else {
None
}
}
}
impl<'a> Iterator for FindChildren<'a> {
type Item = &'a Element;
fn next(&mut self) -> Option<&'a Element> {
use std::borrow::Borrow;
loop {
if let Some(child) = self.child_iter.next() {
if child.tag() == self.tag.borrow() {
return Some(child);
}
} else {
return None;
}
}
}
}
impl<'a> Iterator for FindChildrenMut<'a> {
type Item = &'a mut Element;
fn next(&mut self) -> Option<&'a mut Element> {
use std::borrow::Borrow;
let tag: &QName = self.tag.borrow();
self.child_iter.find(|x| x.tag() == tag)
}
}
impl Element {
pub fn new<'a, Q: AsQName<'a>>(tag: Q) -> Element {
Element::new_with_nsmap(&tag.as_qname(), None)
}
pub fn new_with_namespaces<'a, Q: AsQName<'a>>(tag: Q, reference: &Element) -> Element {
Element::new_with_nsmap(&tag.as_qname(), reference.nsmap.clone())
}
fn new_with_nsmap(tag: &QName<'_>, nsmap: Option<Rc<NamespaceMap>>) -> Element {
let mut rv = Element {
tag: tag.share(),
attributes: BTreeMap::new(),
nsmap,
emit_nsmap: false,
children: vec![],
text: String::new(),
tail: String::new(),
};
if let Some(url) = tag.ns() {
let prefix = rv.get_namespace_prefix(url).unwrap_or("").to_string();
rv.register_namespace(url, Some(&prefix));
}
rv
}
pub fn from_reader<R: Read>(r: R) -> Result<Element, Error> {
let cfg = ParserConfig::new();
let mut reader = cfg.create_reader(r);
loop {
match reader.next_event() {
Ok(XmlEvent::StartElement {
name,
attributes,
namespace,
}) => {
return Element::from_start_element(
name,
attributes,
namespace,
None,
&mut reader,
);
}
Ok(XmlEvent::StartDocument { .. }) | Ok(XmlEvent::ProcessingInstruction { .. }) => {
continue;
}
Ok(_) => {
return Err(Error::UnexpectedEvent {
msg: Cow::Borrowed("xml construct"),
pos: Position::from_xml_position(&reader),
})
}
Err(e) => return Err(e.into()),
}
}
}
pub fn to_writer<W: Write>(&self, w: W) -> Result<(), Error> {
self.to_writer_with_options(w, WriteOptions::new())
}
pub fn to_writer_with_options<W: Write>(
&self,
w: W,
options: WriteOptions,
) -> Result<(), Error> {
let mut writer = options.emitter_config.clone().create_writer(w);
if options.xml_prolog.is_some() {
writer.write(XmlWriteEvent::StartDocument {
version: match options.xml_prolog.unwrap() {
XmlProlog::Version10 => XmlVersion::Version10,
XmlProlog::Version11 => XmlVersion::Version11,
},
encoding: Some("utf-8"),
standalone: None,
})?;
}
self.dump_into_writer(&mut writer)
}
pub fn to_string(&self) -> Result<String, Error> {
let mut out: Vec<u8> = Vec::new();
self.to_writer(&mut out)?;
Ok(String::from_utf8(out).unwrap())
}
fn get_xml_name<'a>(&'a self, qname: &'a QName<'a>) -> Name<'a> {
let mut name = Name::local(qname.name());
if let Some(url) = qname.ns() {
name.namespace = Some(url);
if let Some(prefix) = self.get_namespace_prefix(url) {
if !prefix.is_empty() {
name.prefix = Some(prefix);
}
}
}
name
}
fn dump_into_writer<W: Write>(&self, w: &mut EventWriter<W>) -> Result<(), Error> {
let name = self.get_xml_name(&self.tag);
let mut attributes = Vec::with_capacity(self.attributes.len());
for (k, v) in self.attributes.iter() {
attributes.push(Attribute {
name: self.get_xml_name(k),
value: v,
});
}
let mut namespace = XmlNamespaceMap::empty();
if self.emit_nsmap {
if let Some(ref nsmap) = self.nsmap {
for (prefix, url) in &nsmap.prefix_to_ns {
namespace.put(prefix.borrow(), url.borrow());
}
}
}
w.write(XmlWriteEvent::StartElement {
name,
attributes: Cow::Owned(attributes),
namespace: Cow::Owned(namespace),
})?;
let text = self.text();
if !text.is_empty() {
w.write(XmlWriteEvent::Characters(text))?;
}
for elem in &self.children {
elem.dump_into_writer(w)?;
let text = elem.tail();
if !text.is_empty() {
w.write(XmlWriteEvent::Characters(text))?;
}
}
w.write(XmlWriteEvent::EndElement { name: Some(name) })?;
Ok(())
}
fn from_start_element<R: Read>(
name: OwnedName,
attributes: Vec<OwnedAttribute>,
namespace: XmlNamespaceMap,
parent_nsmap: Option<Rc<NamespaceMap>>,
reader: &mut EventReader<R>,
) -> Result<Element, Error> {
let mut root = Element {
tag: QName::from_owned_name(name),
attributes: BTreeMap::new(),
nsmap: parent_nsmap,
emit_nsmap: false,
children: vec![],
text: String::new(),
tail: String::new(),
};
for attr in attributes {
root.attributes
.insert(QName::from_owned_name(attr.name), attr.value);
}
if !namespace.is_essentially_empty() {
for (prefix, url) in namespace.0.iter() {
root.register_namespace(url, Some(prefix));
}
};
root.parse_children(reader)?;
Ok(root)
}
fn parse_children<R: Read>(&mut self, reader: &mut EventReader<R>) -> Result<(), Error> {
loop {
match reader.next_event() {
Ok(XmlEvent::EndElement { ref name }) => {
if name.local_name == self.tag.name()
&& name.namespace.as_deref() == self.tag.ns()
{
return Ok(());
} else {
return Err(Error::UnexpectedEvent {
msg: Cow::Owned(format!("Unexpected end element {}", &name.local_name)),
pos: Position::from_xml_position(reader),
});
}
}
Ok(XmlEvent::StartElement {
name,
attributes,
namespace,
}) => {
self.children.push(Element::from_start_element(
name,
attributes,
namespace,
self.nsmap.clone(),
reader,
)?);
}
Ok(XmlEvent::Characters(s)) => {
let child_count = self.children.len();
if child_count > 0 {
self.children[child_count - 1].tail = s;
} else {
self.text = s;
}
}
Ok(XmlEvent::StartDocument { .. }) | Ok(XmlEvent::ProcessingInstruction { .. }) => {
continue;
}
Ok(_) => {
return Err(Error::UnexpectedEvent {
msg: Cow::Borrowed("unknown element"),
pos: Position::from_xml_position(reader),
})
}
Err(e) => {
return Err(e.into());
}
}
}
}
pub fn text(&self) -> &str {
&self.text
}
pub fn set_text<S: Into<String>>(&mut self, value: S) -> &mut Element {
self.text = value.into();
self
}
pub fn tail(&self) -> &str {
&self.tail
}
pub fn set_tail<S: Into<String>>(&mut self, value: S) -> &mut Element {
self.tail = value.into();
self
}
pub fn tag(&self) -> &QName {
&self.tag
}
pub fn set_tag<'a>(&mut self, tag: &QName<'a>) -> &mut Element {
self.tag = tag.share();
self
}
pub fn child_count(&self) -> usize {
self.children.len()
}
pub fn get_child(&self, idx: usize) -> Option<&Element> {
self.children.get(idx)
}
pub fn get_child_mut(&mut self, idx: usize) -> Option<&mut Element> {
self.children.get_mut(idx)
}
pub fn remove_child(&mut self, idx: usize) -> Option<Element> {
if self.children.len() > idx {
Some(self.children.remove(idx))
} else {
None
}
}
pub fn retain_children<F>(&mut self, f: F)
where
F: FnMut(&Element) -> bool,
{
self.children.retain(f);
}
pub fn retain_children_mut<F>(&mut self, mut f: F)
where
F: FnMut(&mut Element) -> bool,
{
let old_children = std::mem::take(&mut self.children);
self.children
.extend(old_children.into_iter().filter_map(|mut item| {
if f(&mut item) {
Some(item)
} else {
None
}
}));
}
pub fn append_child(&mut self, child: Element) -> &mut Element {
self.children.push(child);
self
}
pub fn append_new_child<'a, Q: AsQName<'a>>(&'a mut self, tag: Q) -> &'a mut Element {
let child = Element::new_with_namespaces(tag, self);
self.append_child(child);
let idx = self.children.len() - 1;
&mut self.children[idx]
}
pub fn children(&self) -> Children<'_> {
Children {
idx: 0,
element: self,
}
}
pub fn children_mut(&mut self) -> ChildrenMut<'_> {
ChildrenMut {
iter: self.children.iter_mut(),
}
}
pub fn find_all<'a, Q: AsQName<'a>>(&'a self, tag: Q) -> FindChildren<'a> {
FindChildren {
tag: tag.as_qname(),
child_iter: self.children(),
}
}
pub fn find_all_mut<'a, Q: AsQName<'a>>(&'a mut self, tag: Q) -> FindChildrenMut<'a> {
FindChildrenMut {
tag: tag.as_qname(),
child_iter: self.children_mut(),
}
}
pub fn find<'a, Q: AsQName<'a>>(&'a self, tag: Q) -> Option<&'a Element> {
use std::borrow::Borrow;
let tag = tag.as_qname();
for child in self.children() {
if child.tag() == tag.borrow() {
return Some(child);
}
}
None
}
pub fn find_mut<'a, Q: AsQName<'a>>(&'a mut self, tag: Q) -> Option<&'a mut Element> {
self.find_all_mut(tag).next()
}
pub fn get_attr<'a, Q: AsQName<'a>>(&'a self, name: Q) -> Option<&'a str> {
self.attributes.get(&name.as_qname()).map(|x| x.as_str())
}
pub fn set_attr<'a, Q: AsQName<'a>, S: Into<String>>(
&'a mut self,
name: Q,
value: S,
) -> &'a mut Element {
self.attributes
.insert(name.as_qname().share(), value.into());
self
}
pub fn remove_attr<'a, Q: AsQName<'a>>(&'a mut self, name: Q) -> Option<String> {
use std::borrow::Borrow;
let name = name.as_qname();
let name_ref: &QName<'a> = name.borrow();
let name_ref_static: &QName<'static> = unsafe { mem::transmute(name_ref) };
self.attributes.remove(name_ref_static)
}
pub fn attrs(&self) -> Attrs<'_> {
Attrs {
iter: self.attributes.iter(),
}
}
pub fn attr_count(&self) -> usize {
self.attributes.len()
}
fn get_nsmap_mut(&mut self) -> &mut NamespaceMap {
let new_map = match self.nsmap {
Some(ref mut nsmap) if Rc::strong_count(nsmap) == 1 => None,
Some(ref mut nsmap) => Some(Rc::new((**nsmap).clone())),
None => Some(Rc::new(NamespaceMap::new())),
};
if let Some(nsmap) = new_map {
self.nsmap = Some(nsmap);
}
Rc::get_mut(self.nsmap.as_mut().unwrap()).unwrap()
}
pub fn register_namespace(&mut self, url: &str, prefix: Option<&str>) {
if self.get_namespace_prefix(url).is_none()
&& self.get_nsmap_mut().register_if_missing(url, prefix)
{
self.emit_nsmap = true;
}
}
pub fn set_namespace_prefix(&mut self, url: &str, prefix: &str) -> Result<(), Error> {
if self.get_namespace_prefix(url) == Some(prefix) {
Ok(())
} else {
self.get_nsmap_mut().set_prefix(url, prefix)
}
}
pub fn get_namespace_prefix(&self, url: &str) -> Option<&str> {
match url {
NS_EMPTY_URI => Some(""),
NS_XML_URI => Some("xml"),
NS_XMLNS_URI => Some("xmlns"),
_ => {
if let Some(ref nsmap) = self.nsmap {
nsmap.get_prefix(url)
} else {
None
}
}
}
}
pub fn navigate<'a, Q: AsQName<'a>>(&'a self, path: &[Q]) -> Option<&'a Element> {
use std::borrow::Borrow;
let mut node = self;
'outer: for piece in path {
let reftag = piece.as_qname();
for child in node.children() {
if child.tag() == reftag.borrow() {
node = child;
continue 'outer;
}
}
return None;
}
Some(node)
}
}
pub enum XmlProlog {
Version10,
Version11,
}
pub struct WriteOptions {
emitter_config: EmitterConfig,
xml_prolog: Option<XmlProlog>,
}
impl Default for WriteOptions {
fn default() -> WriteOptions {
WriteOptions {
emitter_config: EmitterConfig::new(),
xml_prolog: Some(XmlProlog::Version10),
}
}
}
impl WriteOptions {
pub fn new() -> WriteOptions {
WriteOptions {
..WriteOptions::default()
}
}
pub fn set_xml_prolog(mut self, prolog: Option<XmlProlog>) -> Self {
self.emitter_config = self
.emitter_config
.write_document_declaration(prolog.is_some());
self.xml_prolog = prolog;
self
}
pub fn set_line_separator<I: Into<Cow<'static, str>>>(mut self, sep: I) -> Self {
self.emitter_config = self.emitter_config.line_separator(sep.into());
self
}
pub fn set_indent_string<I: Into<Cow<'static, str>>>(mut self, indent: I) -> Self {
self.emitter_config = self.emitter_config.indent_string(indent.into());
self
}
pub fn set_perform_indent(mut self, yes: bool) -> Self {
self.emitter_config = self.emitter_config.perform_indent(yes);
self
}
pub fn set_normalize_empty_elements(mut self, yes: bool) -> Self {
self.emitter_config = self.emitter_config.normalize_empty_elements(yes);
self
}
pub fn set_cdata_to_characters(mut self, yes: bool) -> Self {
self.emitter_config = self.emitter_config.cdata_to_characters(yes);
self
}
pub fn set_pad_self_closing(mut self, yes: bool) -> Self {
self.emitter_config = self.emitter_config.pad_self_closing(yes);
self
}
pub fn set_autopad_comments(mut self, yes: bool) -> Self {
self.emitter_config = self.emitter_config.autopad_comments(yes);
self
}
}