mirror of
https://github.com/mbilker/kbinxml-rs.git
synced 2026-09-09 19:15:27 -05:00
to_text_xml: implement new function to convert Node and NodeCollection to text XML
This commit is contained in:
10
src/lib.rs
10
src/lib.rs
@@ -30,12 +30,14 @@ mod reader;
|
||||
mod sixbit;
|
||||
mod text_reader;
|
||||
mod to_element;
|
||||
mod to_text_xml;
|
||||
mod value;
|
||||
mod writer;
|
||||
|
||||
use node::NodeDefinition;
|
||||
use node_types::StandardType;
|
||||
use text_reader::TextXmlReader;
|
||||
use to_text_xml::TextXmlWriter;
|
||||
|
||||
// Public exports
|
||||
pub use compression::Compression;
|
||||
@@ -46,6 +48,7 @@ pub use error::{KbinError, KbinErrorKind, Result};
|
||||
pub use node::{Node, NodeCollection};
|
||||
pub use options::Options;
|
||||
pub use to_element::ToElement;
|
||||
pub use to_text_xml::ToTextXml;
|
||||
pub use value::Value;
|
||||
pub use writer::{Writer, Writeable};
|
||||
|
||||
@@ -197,3 +200,10 @@ pub fn to_binary_with_options<T>(options: Options, input: &T) -> Result<Vec<u8>>
|
||||
let mut writer = Writer::with_options(options);
|
||||
writer.to_binary(input)
|
||||
}
|
||||
|
||||
pub fn to_text_xml<T>(input: &T) -> Result<Vec<u8>>
|
||||
where T: ToTextXml
|
||||
{
|
||||
let writer = TextXmlWriter::new();
|
||||
writer.to_text_xml(input)
|
||||
}
|
||||
|
||||
35
src/to_text_xml/mod.rs
Normal file
35
src/to_text_xml/mod.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
use std::io::{Cursor, Write};
|
||||
|
||||
use quick_xml::Writer;
|
||||
|
||||
use error::KbinError;
|
||||
|
||||
mod node;
|
||||
mod node_collection;
|
||||
|
||||
pub trait ToTextXml {
|
||||
fn write<W: Write>(&self, writer: &mut Writer<W>) -> Result<(), KbinError>;
|
||||
}
|
||||
|
||||
pub struct TextXmlWriter {
|
||||
xml_writer: Writer<Cursor<Vec<u8>>>,
|
||||
}
|
||||
|
||||
impl TextXmlWriter {
|
||||
pub fn new() -> Self {
|
||||
let inner = Cursor::new(Vec::new());
|
||||
let xml_writer = Writer::new_with_indent(inner, b' ', 2);
|
||||
|
||||
Self {
|
||||
xml_writer,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_text_xml<T>(mut self, value: &T) -> Result<Vec<u8>, KbinError>
|
||||
where T: ToTextXml
|
||||
{
|
||||
value.write(&mut self.xml_writer)?;
|
||||
|
||||
Ok(self.xml_writer.into_inner().into_inner())
|
||||
}
|
||||
}
|
||||
98
src/to_text_xml/node.rs
Normal file
98
src/to_text_xml/node.rs
Normal file
@@ -0,0 +1,98 @@
|
||||
use std::borrow::Cow;
|
||||
use std::io::Write;
|
||||
|
||||
use quick_xml::Writer;
|
||||
use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
|
||||
use quick_xml::events::attributes::Attribute;
|
||||
|
||||
use error::KbinError;
|
||||
use node::Node;
|
||||
use node_types::StandardType;
|
||||
use to_text_xml::ToTextXml;
|
||||
use value::Value;
|
||||
|
||||
impl ToTextXml for Node {
|
||||
fn write<W: Write>(&self, writer: &mut Writer<W>) -> Result<(), KbinError> {
|
||||
let key = self.key();
|
||||
let mut elem = BytesStart::borrowed(key.as_bytes(), key.as_bytes().len());
|
||||
|
||||
// Write the attributes for the value, but not the value contents.
|
||||
if let Some(value) = self.value() {
|
||||
let node_type = value.standard_type();
|
||||
|
||||
match value {
|
||||
Value::Binary(ref data) => {
|
||||
elem.push_attribute(Attribute {
|
||||
key: b"__size",
|
||||
value: Cow::Owned(data.len().to_string().into_bytes()),
|
||||
});
|
||||
},
|
||||
Value::Array(_, ref values) => {
|
||||
elem.push_attribute(Attribute {
|
||||
key: b"__count",
|
||||
value: Cow::Owned(values.len().to_string().into_bytes()),
|
||||
});
|
||||
},
|
||||
_ => {},
|
||||
};
|
||||
|
||||
// Only add a `__type` attribute if this is not a `NodeStart` node
|
||||
if node_type != StandardType::NodeStart {
|
||||
elem.push_attribute(Attribute {
|
||||
key: b"__type",
|
||||
value: Cow::Borrowed(node_type.name.as_bytes()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(attributes) = self.attributes() {
|
||||
for (key, value) in attributes {
|
||||
elem.push_attribute(Attribute {
|
||||
key: key.as_bytes(),
|
||||
value: Cow::Borrowed(value.as_bytes()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Now write the value contents.
|
||||
let start_elem = if let Some(value) = self.value() {
|
||||
writer.write_event(Event::Start(elem))?;
|
||||
|
||||
let value = value.to_string();
|
||||
let elem = BytesText::from_plain_str(&value);
|
||||
writer.write_event(Event::Text(elem))?;
|
||||
|
||||
None
|
||||
} else {
|
||||
Some(elem)
|
||||
};
|
||||
|
||||
let has_value = start_elem.is_none();
|
||||
let has_children = match self.children() {
|
||||
Some(children) => !children.is_empty(),
|
||||
None => false,
|
||||
};
|
||||
|
||||
// A `Some` value here means the start element was not written
|
||||
if let Some(start_elem) = start_elem {
|
||||
if !has_children {
|
||||
writer.write_event(Event::Empty(start_elem))?;
|
||||
} else {
|
||||
writer.write_event(Event::Start(start_elem))?;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(children) = self.children() {
|
||||
for child in children {
|
||||
child.write(writer)?;
|
||||
}
|
||||
}
|
||||
|
||||
if has_value || has_children {
|
||||
let end_elem = BytesEnd::borrowed(key.as_bytes());
|
||||
writer.write_event(Event::End(end_elem))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
101
src/to_text_xml/node_collection.rs
Normal file
101
src/to_text_xml/node_collection.rs
Normal file
@@ -0,0 +1,101 @@
|
||||
use std::borrow::Cow;
|
||||
use std::io::Write;
|
||||
|
||||
use quick_xml::Writer;
|
||||
use quick_xml::events::{BytesEnd, BytesStart, BytesText, Event};
|
||||
use quick_xml::events::attributes::Attribute;
|
||||
|
||||
use error::{KbinError, KbinErrorKind};
|
||||
use node::NodeCollection;
|
||||
use node_types::StandardType;
|
||||
use to_text_xml::ToTextXml;
|
||||
|
||||
impl ToTextXml for NodeCollection {
|
||||
fn write<W: Write>(&self, writer: &mut Writer<W>) -> Result<(), KbinError> {
|
||||
let base = self.base();
|
||||
let key = base.key()?.ok_or(KbinErrorKind::InvalidState)?;
|
||||
let value = match base.value() {
|
||||
Ok(value) => Some(value),
|
||||
Err(e) => {
|
||||
match e.get_context() {
|
||||
KbinErrorKind::InvalidNodeType(_) => None,
|
||||
_ => return Err(e),
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let mut elem = BytesStart::borrowed(key.as_bytes(), key.as_bytes().len());
|
||||
|
||||
if base.is_array {
|
||||
let values = value.as_ref().ok_or(KbinErrorKind::InvalidState)?.as_array()?;
|
||||
|
||||
elem.push_attribute(Attribute {
|
||||
key: b"__count",
|
||||
value: Cow::Owned(values.len().to_string().into_bytes()),
|
||||
});
|
||||
}
|
||||
|
||||
if base.node_type == StandardType::Binary {
|
||||
let value = value.as_ref().ok_or(KbinErrorKind::InvalidState)?.as_slice()?;
|
||||
|
||||
elem.push_attribute(Attribute {
|
||||
key: b"__size",
|
||||
value: Cow::Owned(value.len().to_string().into_bytes()),
|
||||
});
|
||||
}
|
||||
|
||||
// Only add a `__type` attribute if this is not a `NodeStart` node
|
||||
if base.node_type != StandardType::NodeStart {
|
||||
elem.push_attribute(Attribute {
|
||||
key: b"__type",
|
||||
value: Cow::Borrowed(base.node_type.name.as_bytes()),
|
||||
});
|
||||
}
|
||||
|
||||
for attribute in self.attributes() {
|
||||
let key = attribute.key()?.ok_or(KbinErrorKind::InvalidState)?.into_bytes();
|
||||
let value = attribute.value()?.to_string().into_bytes();
|
||||
|
||||
elem.push_attribute(Attribute {
|
||||
key: &key,
|
||||
value: Cow::Owned(value),
|
||||
});
|
||||
}
|
||||
|
||||
let start_elem = match value {
|
||||
Some(value) => {
|
||||
writer.write_event(Event::Start(elem))?;
|
||||
|
||||
let value = value.to_string();
|
||||
let elem = BytesText::from_plain_str(&value);
|
||||
writer.write_event(Event::Text(elem))?;
|
||||
|
||||
None
|
||||
},
|
||||
None => Some(elem),
|
||||
};
|
||||
|
||||
let has_value = start_elem.is_none();
|
||||
let has_children = !self.children().is_empty();
|
||||
|
||||
// A `Some` value here means the start element was not written
|
||||
if let Some(start_elem) = start_elem {
|
||||
if !has_children {
|
||||
writer.write_event(Event::Empty(start_elem))?;
|
||||
} else {
|
||||
writer.write_event(Event::Start(start_elem))?;
|
||||
}
|
||||
}
|
||||
|
||||
for child in self.children() {
|
||||
child.write(writer)?;
|
||||
}
|
||||
|
||||
if has_value || has_children {
|
||||
let end_elem = BytesEnd::borrowed(key.as_bytes());
|
||||
writer.write_event(Event::End(end_elem))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user