mirror of
https://github.com/nushell/nushell
synced 2024-12-26 04:53:09 +00:00
Merge pull request #104 from jonathandturner/xml
Add (very) preliminary xml open support
This commit is contained in:
commit
fb265eda0f
12 changed files with 147 additions and 0 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -1584,6 +1584,7 @@ dependencies = [
|
|||
"ptree 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"reqwest 0.9.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"roxmltree 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustyline 4.1.0 (git+https://github.com/kkawakam/rustyline.git)",
|
||||
"serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde-hjson 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -2266,6 +2267,14 @@ dependencies = [
|
|||
"uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "roxmltree"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"xmlparser 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-ini"
|
||||
version = "0.13.0"
|
||||
|
@ -3151,6 +3160,11 @@ name = "xml-rs"
|
|||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "xmlparser"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.3"
|
||||
|
@ -3399,6 +3413,7 @@ dependencies = [
|
|||
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
|
||||
"checksum render-tree 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "68ed587df09cfb7ce1bc6fe8f77e24db219f222c049326ccbfb948ec67e31664"
|
||||
"checksum reqwest 0.9.18 (registry+https://github.com/rust-lang/crates.io-index)" = "00eb63f212df0e358b427f0f40aa13aaea010b470be642ad422bcbca2feff2e4"
|
||||
"checksum roxmltree 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "53b0200cbfa8b3f6cfd6076592717d697a1ddc57cb2a8fbfd3d133c06011b579"
|
||||
"checksum rust-ini 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2"
|
||||
"checksum rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc78bfd5acd7bf3e89cffcf899e5cb1a52d6fafa8dec2739ad70c9577a57288"
|
||||
"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8"
|
||||
|
@ -3506,4 +3521,5 @@ dependencies = [
|
|||
"checksum xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"
|
||||
"checksum xi-unicode 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "12ea8eda4b1eb72f02d148402e23832d56a33f55d8c1b2d5bcdde91d79d47cb1"
|
||||
"checksum xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "541b12c998c5b56aa2b4e6f18f03664eef9a4fd0a246a55594efae6cc2d964b5"
|
||||
"checksum xmlparser 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ecec95f00fb0ff019153e64ea520f87d1409769db3e8f4db3ea588638a3e1cee"
|
||||
"checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d"
|
||||
|
|
|
@ -59,6 +59,7 @@ ctrlc = "3.1.3"
|
|||
ptree = "0.2"
|
||||
clipboard = "0.5"
|
||||
reqwest = "0.9"
|
||||
roxmltree = "0.6.0"
|
||||
pretty = "0.5.2"
|
||||
|
||||
[dependencies.pancurses]
|
||||
|
|
|
@ -56,6 +56,7 @@ pub async fn cli() -> Result<(), Box<dyn Error>> {
|
|||
command("size", size::size),
|
||||
command("from-json", from_json::from_json),
|
||||
command("from-toml", from_toml::from_toml),
|
||||
command("from-xml", from_xml::from_xml),
|
||||
command("from-yaml", from_yaml::from_yaml),
|
||||
command("get", get::get),
|
||||
command("open", open::open),
|
||||
|
|
|
@ -8,6 +8,7 @@ crate mod config;
|
|||
crate mod first;
|
||||
crate mod from_json;
|
||||
crate mod from_toml;
|
||||
crate mod from_xml;
|
||||
crate mod from_yaml;
|
||||
crate mod get;
|
||||
crate mod ls;
|
||||
|
|
68
src/commands/from_xml.rs
Normal file
68
src/commands/from_xml.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
use crate::object::{DataDescriptor, Dictionary, Primitive, Value};
|
||||
use crate::prelude::*;
|
||||
|
||||
fn from_node_to_value<'a, 'd>(n: &roxmltree::Node<'a, 'd>) -> Value {
|
||||
if n.is_element() {
|
||||
let name = n.tag_name().name().trim().to_string();
|
||||
|
||||
let mut children_values = vec![];
|
||||
for c in n.children() {
|
||||
children_values.push(from_node_to_value(&c));
|
||||
}
|
||||
|
||||
let children_values: Vec<Value> = children_values
|
||||
.into_iter()
|
||||
.filter(|x| match x {
|
||||
Value::Primitive(Primitive::String(f)) => {
|
||||
if f.trim() == "" {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
_ => true,
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut collected = Dictionary::default();
|
||||
collected.add(
|
||||
DataDescriptor::from(name.clone()),
|
||||
Value::List(children_values),
|
||||
);
|
||||
|
||||
Value::Object(collected)
|
||||
} else if n.is_comment() {
|
||||
Value::Primitive(Primitive::String("<comment>".to_string()))
|
||||
} else if n.is_pi() {
|
||||
Value::Primitive(Primitive::String("<processing_instruction>".to_string()))
|
||||
} else if n.is_text() {
|
||||
Value::Primitive(Primitive::String(n.text().unwrap().to_string()))
|
||||
} else {
|
||||
Value::Primitive(Primitive::String("<unknown>".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
fn from_document_to_value(d: &roxmltree::Document) -> Value {
|
||||
from_node_to_value(&d.root_element())
|
||||
}
|
||||
|
||||
pub fn from_xml_string_to_value(s: String) -> Value {
|
||||
match roxmltree::Document::parse(&s) {
|
||||
Ok(doc) => from_document_to_value(&doc),
|
||||
Err(_) => Value::Error(Box::new(ShellError::string(
|
||||
"Can't convert string from xml".to_string(),
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_xml(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
||||
let out = args.input;
|
||||
Ok(out
|
||||
.map(|a| match a {
|
||||
Value::Primitive(Primitive::String(s)) => ReturnValue::Value(from_xml_string_to_value(s)),
|
||||
_ => ReturnValue::Value(Value::Error(Box::new(ShellError::string(
|
||||
"Trying to convert XML from non-string".to_string(),
|
||||
)))),
|
||||
})
|
||||
.boxed())
|
||||
}
|
|
@ -32,6 +32,18 @@ pub fn get(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
}
|
||||
}
|
||||
|
||||
let amount = args.positional[0].as_i64();
|
||||
|
||||
// If it's a number, get the row instead of the column
|
||||
if let Ok(amount) = amount {
|
||||
return Ok(args
|
||||
.input
|
||||
.skip(amount as u64)
|
||||
.take(1)
|
||||
.map(|v| ReturnValue::Value(v))
|
||||
.boxed());
|
||||
}
|
||||
|
||||
let fields: Result<Vec<String>, _> = args.positional.iter().map(|a| a.as_string()).collect();
|
||||
let fields = fields?;
|
||||
|
||||
|
|
|
@ -103,6 +103,11 @@ pub fn open(args: CommandArgs) -> Result<OutputStream, ShellError> {
|
|||
crate::commands::from_json::from_json_string_to_value(contents),
|
||||
));
|
||||
}
|
||||
Some(x) if x == "xml" && !open_raw => {
|
||||
stream.push_back(ReturnValue::Value(
|
||||
crate::commands::from_xml::from_xml_string_to_value(contents),
|
||||
));
|
||||
}
|
||||
Some(x) if x == "yml" && !open_raw => {
|
||||
stream.push_back(ReturnValue::Value(
|
||||
crate::commands::from_yaml::from_yaml_string_to_value(contents),
|
||||
|
|
|
@ -183,6 +183,18 @@ impl Value {
|
|||
crate fn get_data_by_key(&'a self, name: &str) -> Option<&Value> {
|
||||
match self {
|
||||
Value::Object(o) => o.get_data_by_key(name),
|
||||
Value::List(l) => {
|
||||
for item in l {
|
||||
match item {
|
||||
Value::Object(o) => match o.get_data_by_key(name) {
|
||||
Some(v) => return Some(v),
|
||||
None => {}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
1
tests/open_xml.out
Normal file
1
tests/open_xml.out
Normal file
|
@ -0,0 +1 @@
|
|||
http://www.jonathanturner.org/2015/10/off-to-new-adventures.html
|
3
tests/open_xml.txt
Normal file
3
tests/open_xml.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
cd tests
|
||||
open test.xml | get rss.channel.item.link | echo $it
|
||||
exit
|
22
tests/test.xml
Normal file
22
tests/test.xml
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<channel>
|
||||
<title>Jonathan Turner</title>
|
||||
<link>http://www.jonathanturner.org</link>
|
||||
<atom:link href="http://www.jonathanturner.org/feed.xml" rel="self" type="application/rss+xml" />
|
||||
|
||||
<item>
|
||||
<title>Creating crossplatform Rust terminal apps</title>
|
||||
<description><p><img src="/images/pikachu.jpg" alt="Pikachu animation in Windows" /></p>
|
||||
|
||||
<p><em>Look Mom, Pikachu running in Windows CMD!</em></p>
|
||||
|
||||
<p>Part of the adventure is not seeing the way ahead and going anyway.</p>
|
||||
</description>
|
||||
<pubDate>Mon, 05 Oct 2015 00:00:00 +0000</pubDate>
|
||||
<link>http://www.jonathanturner.org/2015/10/off-to-new-adventures.html</link>
|
||||
<guid isPermaLink="true">http://www.jonathanturner.org/2015/10/off-to-new-adventures.html</guid>
|
||||
</item>
|
||||
|
||||
</channel>
|
||||
</rss>
|
|
@ -64,6 +64,11 @@ mod tests {
|
|||
test_helper("open_json");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn open_xml() {
|
||||
test_helper("open_xml");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn json_roundtrip() {
|
||||
test_helper("json_roundtrip");
|
||||
|
|
Loading…
Reference in a new issue