summaryrefslogtreecommitdiff
path: root/src/library/utility
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-09-25 18:20:39 +0200
committerLaurenz <laurmaedje@gmail.com>2022-09-25 18:20:39 +0200
commitf6adc45638409aaa0feb1f70883c11ed553efe4f (patch)
tree3691cec70698a1952f2b315ed8b602912739acce /src/library/utility
parentfffb55f79a3369fa2dcf39371091c48ff61f55a8 (diff)
XML reading
Diffstat (limited to 'src/library/utility')
-rw-r--r--src/library/utility/data.rs45
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)
+}