diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-09-25 18:20:39 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-09-25 18:20:39 +0200 |
| commit | f6adc45638409aaa0feb1f70883c11ed553efe4f (patch) | |
| tree | 3691cec70698a1952f2b315ed8b602912739acce /src/library/utility | |
| parent | fffb55f79a3369fa2dcf39371091c48ff61f55a8 (diff) | |
XML reading
Diffstat (limited to 'src/library/utility')
| -rw-r--r-- | src/library/utility/data.rs | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/src/library/utility/data.rs b/src/library/utility/data.rs index e3efe6e7..0cff42c1 100644 --- a/src/library/utility/data.rs +++ b/src/library/utility/data.rs @@ -1,5 +1,6 @@ use std::fmt::Write; +use crate::diag::format_xml_like_error; use crate::library::prelude::*; /// Read structured data from a CSV file. @@ -84,3 +85,47 @@ fn format_json_error(error: serde_json::Error) -> String { error.line() ) } + +/// Read structured data from an XML file. +pub fn xml(vm: &mut Vm, args: &mut Args) -> SourceResult<Value> { + let Spanned { v: path, span } = + args.expect::<Spanned<EcoString>>("path to xml file")?; + + let path = vm.locate(&path).at(span)?; + let data = vm.world.file(&path).at(span)?; + let text = std::str::from_utf8(&data).map_err(FileError::from).at(span)?; + + let document = roxmltree::Document::parse(text).map_err(format_xml_error).at(span)?; + + Ok(convert_xml(document.root())) +} + +/// Convert an XML node to a Typst value. +fn convert_xml(node: roxmltree::Node) -> Value { + if node.is_text() { + return Value::Str(node.text().unwrap_or_default().into()); + } + + let children: Array = node.children().map(convert_xml).collect(); + if node.is_root() { + return Value::Array(children); + } + + let tag: Str = node.tag_name().name().into(); + let attrs: Dict = node + .attributes() + .iter() + .map(|attr| (attr.name().into(), attr.value().into())) + .collect(); + + Value::Dict(dict! { + "tag" => tag, + "attrs" => attrs, + "children" => children, + }) +} + +/// Format the user-facing XML error message. +fn format_xml_error(error: roxmltree::Error) -> String { + format_xml_like_error("xml file", error) +} |
