quickxmltoserde

Convert XML to JSON using quick-xml and serde. Inspired by node2object.

Usage examples

Basic

Dependencies:

rust use std::fs::File; use std::io::prelude::*; use quickxml_to_serde::xml_string_to_json; Rust code to perform a conversion: ```rust // read an XML file into a string let mut xmlfile = File::open("test.xml")?; let mut xmlcontents = String::new(); xmlfile.readtostring(&mut xmlcontents)?;

// convert the XML string into JSON with default config params let json = xmlstringtojson(xmlcontents, &Config::newwithdefaults());

println!("{}", json); ```

Custom config

The following config example changes the default behavior to:

  1. Treat numbers starting with 0 as strings. E.g. 0001 will be "0001"
  2. Do not prefix JSON properties created from attributes
  3. Use text as the JSON property name for values of XML text nodes where the text is mixed with other nodes
  4. Exclude empty elements from the output

rust let conf = Config::new_with_custom_values(true, "", "text", NullValue::Ignore);

Enforcing JSON types

Strings

The default for this library is to attempt to infer scalar data types, which can be int, float, bool or string in JSON. Sometimes it is not desirable like in the example below. Let's assume that attribute id is always numeric and can be safely converted to JSON integer. The card_number element looks like a number for the first two users and is a string for the third one. This inconsistency in JSON typing makes it difficult to deserialize the structure, so we may be better off telling the converter to use a particular JSON data type for some XML nodes. xml <users> <user id="1"> <name>Andrew</name> <card_number>000156</card_number> </user> <user id="2"> <name>John</name> <card_number>100263</card_number> </user> <user id="3"> <name>Mary</name> <card_number>100263a</card_number> </user> </users>

Use quickxml_to_serde = { version = "0.4", features = ["json_types"] } feature in your Cargo.toml file to enable support for enforcing JSON types for some XML nodes using xPath-like notations.

Sample XML document: xml <a attr1="007"><b attr1="7">true</b></a> Configuration to make attribute attr1="007" always come out as a JSON string: rust let conf = Config::new_with_defaults().add_json_type_override("/a/@attr1", JsonArray::Infer(JsonType::AlwaysString)); Configuration to make both attributes and the text node of <b /> always come out as a JSON string: rust let conf = Config::new_with_defaults() .add_json_type_override("/a/@attr1", JsonArray::Infer(JsonType::AlwaysString)) .add_json_type_override("/a/b/@attr1", JsonArray::Infer(JsonType::AlwaysString)) .add_json_type_override("/a/b", JsonArray::Infer(JsonType::AlwaysString));

Boolean

The only two valid boolean values in JSON are true and false. On the other hand, values such as True, False,1 and 0 are common in programming languages and data formats. Use JsonType::Bool(...) type with the list of "true" values to convert arbitrary boolean values into JSON bool.

rust let conf = Config::new_with_defaults() .add_json_type_override("/a/b", JsonArray::Infer(JsonType::Bool(vec!["True","true","1","yes"])));

Arrays

Multiple nodes with the same name are automatically converted into a JSON array. For example, xml <a> <b>1</b> <b>2</b> </a> is converted into json { "a": { "b": [1,2] } } By default, a single element like xml <a> <b>1</b> </a> is converted into a scalar value or a map json { "a": { "b": 1 } }

You can use add_json_type_override() with JsonArray::Always() to create a JSON array regardless of the number of elements so that <a><b>1</b></a> becomes { "a": { "b": [1] } }.

JsonArray::Always() and JsonArray::Infer() can specify what underlying JSON type should be used, e.g. * JsonArray::Infer(JsonType::AlwaysString) - infer array, convert the values to JSON string * JsonArray::Always(JsonType::Infer) - always wrap the values in a JSON array, infer the value types * JsonArray::Always(JsonType::AlwaysString) - always wrap the values in a JSON array and convert values to JSON string

rust let config = Config::new_with_defaults() .add_json_type_override("/a/b", JsonArray::Always(JsonType::AlwaysString));

Conversion of empty XML nodes like <a><b /></a> depends on NullValue setting. For example, rust let config = Config::new_with_custom_values(false, "@", "#text", NullValue::Ignore) .add_json_type_override("/a/b", JsonArray::Always(JsonType::Infer)); converts <a><b /></a> to json {"a": null} and the same config with NullValue::Null converts it to

json {"a": { "b": [null] }}

It is not possible to get an empty array like {"a": { "b": [] }}.


See embedded docs for Config struct and its members for more details.

Conversion specifics

Additional info and examples

See tests.rs for more usage examples.

Edge cases

XML and JSON are not directly compatible for 1:1 conversion without additional hints to the converter. Please, post an issue if you come across any incorrect conversion.