mirror of
https://github.com/nushell/nushell.git
synced 2025-08-20 21:33:58 +02:00
Multiple output types for query xml
(#16459)
This is a breaking change. Refs https://discord.com/channels/601130461678272522/615329862395101194/1406413134402551869 ## Release notes summary - What our users need to know Previously, `query xml` always returned a table, even for scalar results. Now scalar results will be returned as scalars. For example ```nushell open -r tests/fixtures/formats/jt.xml | query xml 'false()' ``` used to return ``` ╭───┬─────────╮ │ # │ false() │ ├───┼─────────┤ │ 0 │ false │ ╰───┴─────────╯ ``` and now it will return just `false`. ## Tasks after submitting <!-- Remove any tasks which aren't relevant for your PR, or add your own --> - [ ] Update the [documentation](https://github.com/nushell/nushell.github.io)
This commit is contained in:
@@ -84,43 +84,27 @@ pub fn execute_xpath_query(
|
|||||||
// build_namespaces(&arguments, &mut context);
|
// build_namespaces(&arguments, &mut context);
|
||||||
let res = xpath.evaluate(&context, document.root());
|
let res = xpath.evaluate(&context, document.root());
|
||||||
|
|
||||||
// Some xpath statements can be long, so let's truncate it with ellipsis
|
|
||||||
let mut key = query_string.clone();
|
|
||||||
if query_string.len() >= 20 {
|
|
||||||
key.truncate(17);
|
|
||||||
key += "...";
|
|
||||||
} else {
|
|
||||||
key = query_string.to_string();
|
|
||||||
};
|
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Ok(r) => {
|
Ok(sxd_xpath::Value::Boolean(b)) => Ok(Value::bool(b, call.head)),
|
||||||
let mut record = Record::new();
|
Ok(sxd_xpath::Value::Number(n)) => Ok(Value::float(n, call.head)),
|
||||||
let mut records: Vec<Value> = vec![];
|
Ok(sxd_xpath::Value::String(s)) => Ok(Value::string(s, call.head)),
|
||||||
|
Ok(sxd_xpath::Value::Nodeset(ns)) => {
|
||||||
match r {
|
// Some xpath statements can be long, so let's truncate it with ellipsis
|
||||||
sxd_xpath::Value::Nodeset(ns) => {
|
let mut key = query_string.clone();
|
||||||
for n in ns.document_order() {
|
if query_string.len() >= 20 {
|
||||||
record.push(key.clone(), Value::string(n.string_value(), call.head));
|
key.truncate(17);
|
||||||
}
|
key += "...";
|
||||||
}
|
} else {
|
||||||
sxd_xpath::Value::Boolean(b) => {
|
key = query_string.to_string();
|
||||||
record.push(key, Value::bool(b, call.head));
|
|
||||||
}
|
|
||||||
sxd_xpath::Value::Number(n) => {
|
|
||||||
record.push(key, Value::float(n, call.head));
|
|
||||||
}
|
|
||||||
sxd_xpath::Value::String(s) => {
|
|
||||||
record.push(key, Value::string(s, call.head));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// convert the cols and vecs to a table by creating individual records
|
let mut records: Vec<Value> = vec![];
|
||||||
// for each item so we can then use a list to make a table
|
for n in ns.document_order() {
|
||||||
for (k, v) in record {
|
records.push(Value::record(
|
||||||
records.push(Value::record(record! { k => v }, call.head))
|
record! {key.clone() => Value::string(n.string_value(), call.head)},
|
||||||
|
call.head,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::list(records, call.head))
|
Ok(Value::list(records, call.head))
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -166,14 +150,7 @@ mod tests {
|
|||||||
|
|
||||||
let actual = query(&call, &text, Some(spanned_str), None).expect("test should not fail");
|
let actual = query(&call, &text, Some(spanned_str), None).expect("test should not fail");
|
||||||
|
|
||||||
let expected = Value::list(
|
assert_eq!(actual, Value::test_float(1.0));
|
||||||
vec![Value::test_record(record! {
|
|
||||||
"count(//a/*[posit..." => Value::test_float(1.0),
|
|
||||||
})],
|
|
||||||
Span::test_data(),
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(actual, expected);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -196,14 +173,7 @@ mod tests {
|
|||||||
|
|
||||||
let actual = query(&call, &text, Some(spanned_str), None).expect("test should not fail");
|
let actual = query(&call, &text, Some(spanned_str), None).expect("test should not fail");
|
||||||
|
|
||||||
let expected = Value::list(
|
assert_eq!(actual, Value::test_float(1.0));
|
||||||
vec![Value::test_record(record! {
|
|
||||||
"count(//*[contain..." => Value::test_float(1.0),
|
|
||||||
})],
|
|
||||||
Span::test_data(),
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(actual, expected);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -243,4 +213,91 @@ mod tests {
|
|||||||
// and yet it should work regardless
|
// and yet it should work regardless
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn number_returns_float() {
|
||||||
|
let call = EvaluatedCall {
|
||||||
|
head: Span::test_data(),
|
||||||
|
positional: vec![],
|
||||||
|
named: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let text = Value::test_string(r#"<?xml version="1.0" encoding="UTF-8"?><elt/>"#);
|
||||||
|
|
||||||
|
let spanned_str: Spanned<String> = Spanned {
|
||||||
|
item: "count(/elt)".to_string(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let actual = query(&call, &text, Some(spanned_str), None).expect("test should not fail");
|
||||||
|
|
||||||
|
assert_eq!(actual, Value::test_float(1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn boolean_returns_bool() {
|
||||||
|
let call = EvaluatedCall {
|
||||||
|
head: Span::test_data(),
|
||||||
|
positional: vec![],
|
||||||
|
named: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let text = Value::test_string(r#"<?xml version="1.0" encoding="UTF-8"?><elt/>"#);
|
||||||
|
|
||||||
|
let spanned_str: Spanned<String> = Spanned {
|
||||||
|
item: "false()".to_string(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let actual = query(&call, &text, Some(spanned_str), None).expect("test should not fail");
|
||||||
|
|
||||||
|
assert_eq!(actual, Value::test_bool(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn string_returns_string() {
|
||||||
|
let call = EvaluatedCall {
|
||||||
|
head: Span::test_data(),
|
||||||
|
positional: vec![],
|
||||||
|
named: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let text = Value::test_string(r#"<?xml version="1.0" encoding="UTF-8"?><elt/>"#);
|
||||||
|
|
||||||
|
let spanned_str: Spanned<String> = Spanned {
|
||||||
|
item: "local-name(/elt)".to_string(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let actual = query(&call, &text, Some(spanned_str), None).expect("test should not fail");
|
||||||
|
|
||||||
|
assert_eq!(actual, Value::test_string("elt"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nodeset_returns_table() {
|
||||||
|
let call = EvaluatedCall {
|
||||||
|
head: Span::test_data(),
|
||||||
|
positional: vec![],
|
||||||
|
named: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let text = Value::test_string(r#"<?xml version="1.0" encoding="UTF-8"?><elt>hello</elt>"#);
|
||||||
|
|
||||||
|
let spanned_str: Spanned<String> = Spanned {
|
||||||
|
item: "/elt".to_string(),
|
||||||
|
span: Span::test_data(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let actual = query(&call, &text, Some(spanned_str), None).expect("test should not fail");
|
||||||
|
|
||||||
|
let expected = Value::list(
|
||||||
|
vec![Value::test_record(record! {
|
||||||
|
"/elt" => Value::string("hello", Span::test_data()),
|
||||||
|
})],
|
||||||
|
Span::test_data(),
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(actual, expected);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user