Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More general write methods #20

Open
dyst5422 opened this issue Feb 9, 2020 · 4 comments
Open

More general write methods #20

dyst5422 opened this issue Feb 9, 2020 · 4 comments

Comments

@dyst5422
Copy link
Contributor

dyst5422 commented Feb 9, 2020

Now that parse_all returns Vec, we need a way to write this back out so that original comment, cdata, etc are included.

@eminence
Copy link
Owner

eminence commented Feb 9, 2020

Something like:

pub fn write_all<W: Write>(w: W, nodes: &[XMLNode]) -> io::Result<()>;

?

@dyst5422
Copy link
Contributor Author

dyst5422 commented Feb 9, 2020

Yeah. I have an external prototype I've been using that separates out the event emission from the write, so that one could write multiple XMLNodes/Elements to the same write stream as separate operations.

Note that the emit methods should be internalized with self.

pub fn write_tree<W: std::io::Write>(
    xml_tree: Vec<XMLNode>,
    w: &mut W,
) -> Result<(), xml::writer::Error> {
    write_tree_with_config(xml_tree, w, EmitterConfig::new())
}

pub fn write_tree_with_config<W: std::io::Write>(
    xml_tree: Vec<XMLNode>,
    w: &mut W,
    config: xml::writer::EmitterConfig,
) -> Result<(), xml::writer::Error> {
    use xml::common::XmlVersion;
    use xml::writer::events::XmlEvent;
    use xml::writer::EventWriter;

    let mut emitter = EventWriter::new_with_config(w, config);
    emitter.write(XmlEvent::StartDocument {
        version: XmlVersion::Version10,
        encoding: None,
        standalone: None,
    })?;
    for node in &xml_tree {
        xmlnode_emit(node, &mut emitter)?;
    }
    Ok(())
}

pub fn xmlnode_emit<B: std::io::Write>(node: &XMLNode, emitter: &mut xml::writer::EventWriter<B>) -> Result<(), xml::writer::Error> {
    use xml::writer::events::XmlEvent;
    match node {
        XMLNode::Element(elem) => xmlelement_emit(elem, emitter)?,
        XMLNode::Text(text) => emitter.write(XmlEvent::Characters(text))?,
        XMLNode::Comment(comment) => emitter.write(XmlEvent::Comment(comment))?,
        XMLNode::CData(cdata) => emitter.write(XmlEvent::CData(cdata))?,
        XMLNode::ProcessingInstruction(name, data) => match data.to_owned() {
            Some(string) => emitter.write(XmlEvent::ProcessingInstruction {
                name,
                data: Some(&string),
            })?,
            None => emitter.write(XmlEvent::ProcessingInstruction { name, data: None })?,
        },
    }
    Ok(())
}

pub fn xmlelement_emit<B: std::io::Write>(element: &xmltree::Element, emitter: &mut xml::writer::EventWriter<B>) -> Result<(), xml::writer::Error> {
    use xml::attribute::Attribute;
    use xml::name::Name;
    use xml::namespace::Namespace;
    use std::borrow::Cow;
    use xml::writer::events::XmlEvent;

    let mut name = Name::local(&element.name);
    if let Some(ref ns) = element.namespace {
        name.namespace = Some(ns);
    }
    if let Some(ref p) = element.prefix {
        name.prefix = Some(p);
    }

    let mut attributes = Vec::with_capacity(element.attributes.len());
    for (k, v) in &element.attributes {
        attributes.push(Attribute {
            name: Name::local(k),
            value: v,
        });
    }

    let empty_ns = Namespace::empty();
    let namespace = if let Some(ref ns) = element.namespaces {
        Cow::Borrowed(ns)
    } else {
        Cow::Borrowed(&empty_ns)
    };

    emitter.write(XmlEvent::StartElement {
        name,
        attributes: Cow::Owned(attributes),
        namespace,
    })?;
    for node in &element.children {
        xmlnode_emit(node, emitter)?;
    }
    emitter.write(XmlEvent::EndElement { name: Some(name) })?;
    Ok(())
}

Edit:
Just realized I should have taken &[XMLNode] as inputs rather than vectors.

@dyst5422
Copy link
Contributor Author

dyst5422 commented Feb 9, 2020

Also, I'm completely open to changes in external API shape. I'm really jumping around in the best api myself - whether to have methods that consume XMLNode to write, or having a trait implemented on Vec<XMLNode>, etc etc.

@dvtomas
Copy link

dvtomas commented Jul 13, 2020

I would also appreciate making Element::_write public, or having some other way to be able to build up the XML incrementally from individual Elements over a longer course of time, without being forced to wait until all of them are available.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants