Skip to content

Commit 88e0624

Browse files
piedoomdoomy
and
doomy
authored
Added XML support for load_data (#1769)
Co-authored-by: doomy <[email protected]>
1 parent a67370b commit 88e0624

File tree

6 files changed

+107
-5
lines changed

6 files changed

+107
-5
lines changed

Cargo.lock

+31
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/libs/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ csv = "1"
1010
base64 = "0.13"
1111
serde_json = "1"
1212
serde_yaml = "0.8"
13+
quickxml_to_serde = "0.5"
1314
url = "2"
1415
syntect = "4"
1516
once_cell = "1"

components/libs/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub use num_format;
2121
pub use once_cell;
2222
pub use percent_encoding;
2323
pub use pulldown_cmark;
24+
pub use quickxml_to_serde;
2425
pub use rayon;
2526
pub use regex;
2627
pub use relative_path;

components/templates/src/global_fns/load_data.rs

+61
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ enum OutputFormat {
4646
Csv,
4747
Bibtex,
4848
Plain,
49+
Xml,
4950
}
5051

5152
impl FromStr for OutputFormat {
@@ -57,6 +58,7 @@ impl FromStr for OutputFormat {
5758
"csv" => Ok(OutputFormat::Csv),
5859
"json" => Ok(OutputFormat::Json),
5960
"bibtex" => Ok(OutputFormat::Bibtex),
61+
"xml" => Ok(OutputFormat::Xml),
6062
"plain" => Ok(OutputFormat::Plain),
6163
format => Err(format!("Unknown output format {}", format).into()),
6264
}
@@ -70,6 +72,7 @@ impl OutputFormat {
7072
OutputFormat::Csv => "text/csv",
7173
OutputFormat::Toml => "application/toml",
7274
OutputFormat::Bibtex => "application/x-bibtex",
75+
OutputFormat::Xml => "text/xml",
7376
OutputFormat::Plain => "text/plain",
7477
})
7578
}
@@ -368,6 +371,7 @@ impl TeraFn for LoadData {
368371
OutputFormat::Csv => load_csv(data),
369372
OutputFormat::Json => load_json(data),
370373
OutputFormat::Bibtex => load_bibtex(data),
374+
OutputFormat::Xml => load_xml(data),
371375
OutputFormat::Plain => to_value(data).map_err(|e| e.into()),
372376
};
373377

@@ -502,6 +506,42 @@ fn load_csv(csv_data: String) -> Result<Value> {
502506
to_value(csv_value).map_err(|err| err.into())
503507
}
504508

509+
/// Parse an XML string and convert it to a Tera Value
510+
///
511+
/// An example XML file `example.xml` could be:
512+
/// ```xml
513+
/// <root>
514+
/// <headers>Number</headers>
515+
/// <headers>Title</headers>
516+
/// <records>
517+
/// <item>1</item>
518+
/// <item>Gutenberg</item>
519+
/// </records>
520+
/// <records>
521+
/// <item>2</item>
522+
/// <item>Printing</item>
523+
/// </records>
524+
/// </root>
525+
/// ```
526+
/// The json value output would be:
527+
/// ```json
528+
/// {
529+
/// "root": {
530+
/// "headers": ["Number", "Title"],
531+
/// "records": [
532+
/// ["1", "Gutenberg"],
533+
/// ["2", "Printing"]
534+
/// ]
535+
/// }
536+
/// }
537+
/// ```
538+
fn load_xml(xml_data: String) -> Result<Value> {
539+
let xml_content: Value =
540+
libs::quickxml_to_serde::xml_string_to_json(xml_data, &Default::default())
541+
.map_err(|e| format!("{:?}", e))?;
542+
Ok(xml_content)
543+
}
544+
505545
#[cfg(test)]
506546
mod tests {
507547
use super::{DataSource, LoadData, OutputFormat};
@@ -1007,6 +1047,27 @@ mod tests {
10071047
)
10081048
}
10091049

1050+
#[test]
1051+
fn can_load_xml() {
1052+
let static_fn = LoadData::new(PathBuf::from("../utils/test-files"), None, PathBuf::new());
1053+
let mut args = HashMap::new();
1054+
args.insert("path".to_string(), to_value("test.xml").unwrap());
1055+
let result = static_fn.call(&args.clone()).unwrap();
1056+
1057+
assert_eq!(
1058+
result,
1059+
json!({
1060+
"root": {
1061+
"key": "value",
1062+
"array": [1, 2, 3],
1063+
"subpackage": {
1064+
"subkey": 5
1065+
}
1066+
}
1067+
})
1068+
)
1069+
}
1070+
10101071
#[test]
10111072
fn is_load_remote_data_using_post_method_with_different_body_not_cached() {
10121073
let _mjson = mock("POST", "/kr1zdgbm4y3")

components/utils/test-files/test.xml

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<root>
2+
<key>value</key>
3+
<array>1</array>
4+
<array>2</array>
5+
<array>3</array>
6+
<subpackage>
7+
<subkey>5</subkey>
8+
</subpackage>
9+
</root>

docs/content/documentation/templates/overview.md

+4-5
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ The method returns a map containing `width`, `height` and `format` (the lowercas
258258
```
259259

260260
### `load_data`
261-
Loads data from a file or URL. Supported file types include *toml*, *json*, *csv* and *bibtex* and only supports UTF-8 encoding.
261+
Loads data from a file or URL. Supported file types include *toml*, *json*, *csv*, *bibtex* and *xml* and only supports UTF-8 encoding.
262262
Any other file type will be loaded as plain text.
263263

264264
The `path` argument specifies the path to a local data file, according to the [File Searching Logic](@/documentation/templates/overview.md#file-searching-logic).
@@ -283,17 +283,16 @@ The snippet below outputs the HTML from a Wikipedia page, or "No data found" if
283283
```
284284

285285
The optional `format` argument allows you to specify and override which data type is contained
286-
within the specified file or URL. Valid entries are `toml`, `json`, `csv`, `bibtex`
287-
or `plain`. If the `format` argument isn't specified, then the path extension is used.
286+
within the specified file or URL. Valid entries are `toml`, `json`, `csv`, `bibtex`, `xml` or `plain`. If the `format` argument isn't specified, then the path extension is used.
288287

289288

290289
```jinja2
291290
{% set data = load_data(path="content/blog/story/data.txt", format="json") %}
292291
```
293292

294-
Use the `plain` format for when your file has a toml/json/csv extension but you want to load it as plain text.
293+
Use the `plain` format for when your file has a supported extension but you want to load it as plain text.
295294

296-
For *toml* and *json*, the data is loaded into a structure matching the original data file;
295+
For *toml*, *json* and *xml*, the data is loaded into a structure matching the original data file;
297296
however, for *csv* there is no native notion of such a structure. Instead, the data is separated
298297
into a data structure containing *headers* and *records*. See the example below to see
299298
how this works.

0 commit comments

Comments
 (0)