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 | |
| parent | fffb55f79a3369fa2dcf39371091c48ff61f55a8 (diff) | |
XML reading
Diffstat (limited to 'src/library')
| -rw-r--r-- | src/library/mod.rs | 1 | ||||
| -rw-r--r-- | src/library/prelude.rs | 6 | ||||
| -rw-r--r-- | src/library/utility/data.rs | 45 |
3 files changed, 50 insertions, 2 deletions
diff --git a/src/library/mod.rs b/src/library/mod.rs index d806f298..91e4671c 100644 --- a/src/library/mod.rs +++ b/src/library/mod.rs @@ -98,6 +98,7 @@ pub fn new() -> Scope { std.def_fn("lorem", utility::lorem); std.def_fn("csv", utility::csv); std.def_fn("json", utility::json); + std.def_fn("xml", utility::xml); // Predefined colors. std.define("black", Color::BLACK); diff --git a/src/library/prelude.rs b/src/library/prelude.rs index 44d1af7f..03bef51e 100644 --- a/src/library/prelude.rs +++ b/src/library/prelude.rs @@ -9,10 +9,12 @@ pub use std::sync::Arc; pub use comemo::Tracked; pub use typst_macros::node; -pub use crate::diag::{with_alternative, At, SourceError, SourceResult, StrResult}; +pub use crate::diag::{ + with_alternative, At, FileError, FileResult, SourceError, SourceResult, StrResult, +}; pub use crate::eval::{ Arg, Args, Array, Cast, Dict, Dynamic, Func, Node, RawAlign, RawLength, RawStroke, - Scope, Smart, Value, Vm, + Scope, Smart, Str, Value, Vm, }; pub use crate::frame::*; pub use crate::geom::*; 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) +} |
