mirror of
https://github.com/nushell/nushell.git
synced 2025-04-24 21:28:20 +02:00
Add self-closed tag support for to xml
(#11577)
# Description This PR closes #11524 Add `to xml --self-closed` flag to output empty tags as self close. For example:  # User-Facing Changes New `to xml` flag `--self-closed`. # Tests + Formatting Added new example for `to xml` command and new test for self-closed tags.
This commit is contained in:
parent
56067da39c
commit
ff290a5c3d
@ -34,6 +34,11 @@ impl Command for ToXml {
|
|||||||
"Only escape mandatory characters in text and attributes",
|
"Only escape mandatory characters in text and attributes",
|
||||||
Some('p'),
|
Some('p'),
|
||||||
)
|
)
|
||||||
|
.switch(
|
||||||
|
"self-closed",
|
||||||
|
"Output empty tags as self closing",
|
||||||
|
Some('s'),
|
||||||
|
)
|
||||||
.category(Category::Formats)
|
.category(Category::Formats)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,6 +82,13 @@ Additionally any field which is: empty record, empty list or null, can be omitte
|
|||||||
result: Some(Value::test_string(
|
result: Some(Value::test_string(
|
||||||
r#"<note a="'qwe'\">"'</note>"#
|
r#"<note a="'qwe'\">"'</note>"#
|
||||||
))
|
))
|
||||||
|
},
|
||||||
|
Example {
|
||||||
|
description: "Save space using self-closed tags",
|
||||||
|
example: r#"{tag: root content: [[tag]; [a] [b] [c]]} | to xml --self-closed"#,
|
||||||
|
result: Some(Value::test_string(
|
||||||
|
r#"<root><a/><b/><c/></root>"#
|
||||||
|
))
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -95,8 +107,9 @@ Additionally any field which is: empty record, empty list or null, can be omitte
|
|||||||
let head = call.head;
|
let head = call.head;
|
||||||
let indent: Option<Spanned<i64>> = call.get_flag(engine_state, stack, "indent")?;
|
let indent: Option<Spanned<i64>> = call.get_flag(engine_state, stack, "indent")?;
|
||||||
let partial_escape = call.has_flag(engine_state, stack, "partial-escape")?;
|
let partial_escape = call.has_flag(engine_state, stack, "partial-escape")?;
|
||||||
|
let self_closed = call.has_flag(engine_state, stack, "self-closed")?;
|
||||||
|
|
||||||
let job = Job::new(indent, partial_escape);
|
let job = Job::new(indent, partial_escape, self_closed);
|
||||||
let input = input.try_expand_range()?;
|
let input = input.try_expand_range()?;
|
||||||
job.run(input, head)
|
job.run(input, head)
|
||||||
}
|
}
|
||||||
@ -105,10 +118,11 @@ Additionally any field which is: empty record, empty list or null, can be omitte
|
|||||||
struct Job {
|
struct Job {
|
||||||
writer: quick_xml::Writer<Cursor<Vec<u8>>>,
|
writer: quick_xml::Writer<Cursor<Vec<u8>>>,
|
||||||
partial_escape: bool,
|
partial_escape: bool,
|
||||||
|
self_closed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Job {
|
impl Job {
|
||||||
fn new(indent: Option<Spanned<i64>>, partial_escape: bool) -> Self {
|
fn new(indent: Option<Spanned<i64>>, partial_escape: bool, self_closed: bool) -> Self {
|
||||||
let writer = indent.as_ref().map_or_else(
|
let writer = indent.as_ref().map_or_else(
|
||||||
|| quick_xml::Writer::new(Cursor::new(Vec::new())),
|
|| quick_xml::Writer::new(Cursor::new(Vec::new())),
|
||||||
|p| quick_xml::Writer::new_with_indent(Cursor::new(Vec::new()), b' ', p.item as usize),
|
|p| quick_xml::Writer::new_with_indent(Cursor::new(Vec::new()), b' ', p.item as usize),
|
||||||
@ -117,6 +131,7 @@ impl Job {
|
|||||||
Self {
|
Self {
|
||||||
writer,
|
writer,
|
||||||
partial_escape,
|
partial_escape,
|
||||||
|
self_closed,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -424,12 +439,18 @@ impl Job {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let self_closed = self.self_closed && children.is_empty();
|
||||||
let attributes = Self::parse_attributes(attrs)?;
|
let attributes = Self::parse_attributes(attrs)?;
|
||||||
let mut open_tag_event = BytesStart::new(tag.clone());
|
let mut open_tag = BytesStart::new(tag.clone());
|
||||||
self.add_attributes(&mut open_tag_event, &attributes);
|
self.add_attributes(&mut open_tag, &attributes);
|
||||||
|
let open_tag_event = if self_closed {
|
||||||
|
Event::Empty(open_tag)
|
||||||
|
} else {
|
||||||
|
Event::Start(open_tag)
|
||||||
|
};
|
||||||
|
|
||||||
self.writer
|
self.writer
|
||||||
.write_event(Event::Start(open_tag_event))
|
.write_event(open_tag_event)
|
||||||
.map_err(|_| ShellError::CantConvert {
|
.map_err(|_| ShellError::CantConvert {
|
||||||
to_type: "XML".to_string(),
|
to_type: "XML".to_string(),
|
||||||
from_type: Type::Record(vec![]).to_string(),
|
from_type: Type::Record(vec![]).to_string(),
|
||||||
@ -441,15 +462,18 @@ impl Job {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.try_for_each(|child| self.write_xml_entry(child, false))?;
|
.try_for_each(|child| self.write_xml_entry(child, false))?;
|
||||||
|
|
||||||
let close_tag_event = BytesEnd::new(tag);
|
if !self_closed {
|
||||||
|
let close_tag_event = Event::End(BytesEnd::new(tag));
|
||||||
self.writer
|
self.writer
|
||||||
.write_event(Event::End(close_tag_event))
|
.write_event(close_tag_event)
|
||||||
.map_err(|_| ShellError::CantConvert {
|
.map_err(|_| ShellError::CantConvert {
|
||||||
to_type: "XML".to_string(),
|
to_type: "XML".to_string(),
|
||||||
from_type: Type::Record(vec![]).to_string(),
|
from_type: Type::Record(vec![]).to_string(),
|
||||||
span: entry_span,
|
span: entry_span,
|
||||||
help: Some("Failure writing tag to xml".into()),
|
help: Some("Failure writing tag to xml".into()),
|
||||||
})
|
})?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_attributes(attrs: Record) -> Result<IndexMap<String, String>, ShellError> {
|
fn parse_attributes(attrs: Record) -> Result<IndexMap<String, String>, ShellError> {
|
||||||
|
@ -91,3 +91,22 @@ fn to_xml_pi_comment_not_escaped() {
|
|||||||
));
|
));
|
||||||
assert_eq!(actual.out, r#"<a><?qwe "'<>&?><!--"'<>&--></a>"#);
|
assert_eq!(actual.out, r#"<a><?qwe "'<>&?><!--"'<>&--></a>"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn to_xml_self_closed() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: "tests/fixtures/formats", pipeline(
|
||||||
|
r#"
|
||||||
|
{
|
||||||
|
tag: root
|
||||||
|
content: [
|
||||||
|
[tag attributes content];
|
||||||
|
[a null null]
|
||||||
|
[b {e: r} null]
|
||||||
|
[c {t: y} []]
|
||||||
|
]
|
||||||
|
} | to xml --self-closed
|
||||||
|
"#
|
||||||
|
));
|
||||||
|
assert_eq!(actual.out, r#"<root><a/><b e="r"/><c t="y"/></root>"#);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user