nushell/src/commands/from_xml.rs

84 lines
2.6 KiB
Rust
Raw Normal View History

2019-07-09 06:31:26 +02:00
use crate::object::{Dictionary, Primitive, SpannedDictBuilder, Value};
2019-06-11 08:26:03 +02:00
use crate::prelude::*;
2019-07-09 06:31:26 +02:00
fn from_node_to_value<'a, 'd>(
n: &roxmltree::Node<'a, 'd>,
span: impl Into<Span>,
) -> Spanned<Value> {
let span = span.into();
2019-06-11 08:26:03 +02:00
if n.is_element() {
let name = n.tag_name().name().trim().to_string();
let mut children_values = vec![];
for c in n.children() {
2019-07-09 06:31:26 +02:00
children_values.push(from_node_to_value(&c, span));
2019-06-11 08:26:03 +02:00
}
2019-07-08 18:44:53 +02:00
let children_values: Vec<Spanned<Value>> = children_values
2019-06-11 08:26:03 +02:00
.into_iter()
.filter(|x| match x {
2019-07-09 06:31:26 +02:00
Spanned {
item: Value::Primitive(Primitive::String(f)),
..
} => {
2019-06-11 08:26:03 +02:00
if f.trim() == "" {
2019-06-15 20:36:17 +02:00
false
2019-06-11 08:26:03 +02:00
} else {
true
}
}
_ => true,
})
.collect();
let mut collected = Dictionary::default();
2019-07-09 06:31:26 +02:00
collected.add(name.clone(), Value::List(children_values).spanned(span));
2019-06-11 08:26:03 +02:00
2019-07-09 06:31:26 +02:00
collected.into_spanned_value()
2019-06-11 08:26:03 +02:00
} else if n.is_comment() {
2019-07-09 06:31:26 +02:00
Value::string("<comment>").spanned(span)
2019-06-11 08:26:03 +02:00
} else if n.is_pi() {
2019-07-09 06:31:26 +02:00
Value::string("<processing_instruction>").spanned(span)
2019-06-11 08:26:03 +02:00
} else if n.is_text() {
2019-07-09 06:31:26 +02:00
Value::string(n.text().unwrap()).spanned(span)
2019-06-11 08:26:03 +02:00
} else {
2019-07-09 06:31:26 +02:00
Value::string("<unknown>").spanned(span)
2019-06-11 08:26:03 +02:00
}
}
2019-07-09 06:31:26 +02:00
fn from_document_to_value(d: &roxmltree::Document, span: impl Into<Span>) -> Spanned<Value> {
from_node_to_value(&d.root_element(), span)
2019-06-11 08:26:03 +02:00
}
2019-07-09 06:31:26 +02:00
pub fn from_xml_string_to_value(
s: String,
span: impl Into<Span>,
) -> Result<Spanned<Value>, Box<dyn std::error::Error>> {
2019-06-16 01:03:49 +02:00
let parsed = roxmltree::Document::parse(&s)?;
2019-07-09 06:31:26 +02:00
Ok(from_document_to_value(&parsed, span))
2019-06-11 08:26:03 +02:00
}
pub fn from_xml(args: CommandArgs) -> Result<OutputStream, ShellError> {
let out = args.input;
2019-06-15 20:36:17 +02:00
let span = args.name_span;
2019-06-11 08:26:03 +02:00
Ok(out
.values
2019-07-08 18:44:53 +02:00
.map(move |a| match a.item {
2019-07-09 06:31:26 +02:00
Value::Primitive(Primitive::String(s)) => match from_xml_string_to_value(s, span) {
2019-07-08 18:44:53 +02:00
Ok(x) => ReturnSuccess::value(x.spanned(a.span)),
Err(_) => Err(ShellError::maybe_labeled_error(
"Could not parse as XML",
"piped data failed XML parse",
span,
)),
2019-06-16 01:03:49 +02:00
},
_ => Err(ShellError::maybe_labeled_error(
2019-06-16 01:03:49 +02:00
"Expected string values from pipeline",
"expects strings from pipeline",
2019-06-15 20:36:17 +02:00
span,
)),
2019-06-11 08:26:03 +02:00
})
.to_output_stream())
2019-06-11 08:26:03 +02:00
}