This post is about reading an EPCIS 1.2 XML into a Struct instance. EPCIS stands for Electronic Product Code Information Services. It is a global GS1 Standard for creating and sharing visibility event data in certain industries, both within and across enterprises, to enable users to gain a shared view of physical or digital objects within a relevant business context. This enables systems from different organizations to speak to each other in certain vocabulary known to all of them.
For writing EPCIS 1.2 XML to files, please read Generate EPCIS 1.2 XML.
Requirements
We have the following items used for this post.
- Rust 1.39.0
- Cargo 1.39.0
- Rust crates
- serde_derive 1.0.102
- serde 1.0.102
- serde-xml-rs 0.3.1
- IntelliJ
- Rust plugin for Intellij IDEA
Input EPCIS XML
For our input file, we’ll use an existing file to read from. It is an EPCIS 1.2 as defined in the second line where schemaVersion is set to “1.2”. It also has 2 major elements – EPCISHeader and EPCISBody.
EPCIS Structs
The structs for our codes represent some elements in the XML document. This is to easily read EPCIS XML into a struct instance. Most of them have the same name as the XML element they represent. Some structs contain other structs as some XML elements contain other elements.
1 2 3 4 5 6 7 | #[derive(Deserialize, Debug)] struct EPCISDocument { #[serde(rename = "EPCISHeader")] epcis_header: EPCISHeader, #[serde(rename = "EPCISBody")] epcis_body: EPCISBody, } |
1 2 3 4 5 | #[derive(Deserialize, Debug)] struct EPCISHeader { #[serde(rename = "StandardBusinessDocumentHeader")] standard_business_document_header: StandardBusinessDocumentHeader } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #[derive(Deserialize, Debug)] struct StandardBusinessDocumentHeader { #[serde(rename = "HeaderVersion")] header_version: String, #[serde(rename = "Sender")] sender: SenderIdentifier, #[serde(rename = "Receiver")] receiver: ReceiverIdentifier, #[serde(rename = "DocumentIdentification")] document_id: DocumentIdentification, } |
1 2 3 4 5 | #[derive(Deserialize, Debug)] struct SenderIdentifier { #[serde(rename = "Identifier")] identifier: SenderReceiverIdentifier, } |
1 2 3 4 5 | #[derive(Deserialize, Debug)] struct ReceiverIdentifier { #[serde(rename = "Identifier")] identifier: SenderReceiverIdentifier, } |
1 2 3 4 5 6 7 | #[derive(Deserialize, Debug)] struct SenderReceiverIdentifier { #[serde(rename = "Authority")] authority: String, #[serde(rename = "$value")] element_content: String, } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #[derive(Deserialize, Debug)] struct DocumentIdentification { #[serde(rename = "Standard")] standard: String, #[serde(rename = "TypeVersion")] type_version: String, #[serde(rename = "InstanceIdentifier")] instance_identifier: String, #[serde(rename = "Type")] doc_id_type: String, #[serde(rename = "CreationDateAndTime")] creation_date_time: String, } |
1 2 3 4 5 | #[derive(Deserialize, Debug)] struct EPCISBody { #[serde(rename = "EventList")] event_list: EventList } |
1 2 3 4 5 6 7 8 | #[derive(Deserialize, Debug)] struct EventList { #[serde(rename = "ObjectEvent", default)] event_object: Vec<ObjectEvent>, #[serde(rename = "AggregationEvent", default)] aggregation_object: Vec<AggregationEvent> } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #[derive(Deserialize, Debug)] struct ObjectEvent { #[serde(rename = "eventTime")] event_time: String, #[serde(rename = "eventTimeZoneOffset")] event_time_zone_offset: String, #[serde(rename = "epcList")] epc_list: EpcList, action: String, #[serde(rename = "bizStep")] biz_step: String, disposition: String, #[serde(rename = "readPoint")] read_point: ReadPoint, #[serde(rename = "bizLocation")] biz_location: BizLocation, #[serde(default)] extension: Extension, } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #[derive(Deserialize, Debug)] struct AggregationEvent { #[serde(rename = "eventTime")] event_time: String, #[serde(rename = "eventTimeZoneOffset")] event_time_zone_offset: String, #[serde(rename = "childEPCs")] child_epc_list: EpcList, action: String, #[serde(rename = "bizStep")] biz_step: String, disposition: String, #[serde(rename = "readPoint")] read_point: ReadPoint, #[serde(rename = "bizLocation")] biz_location: BizLocation, } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | #[derive(Deserialize, Debug)] struct EpcList { epc: Vec<String>, } #[derive(Deserialize, Debug)] struct Ilmd { #[serde(rename = "lotNumber")] lot_number: String, #[serde(rename = "itemExpirationDate")] item_expiration_date: String, } impl Default for Ilmd { fn default() -> Self { Ilmd { lot_number: "".to_string(), item_expiration_date: "".to_string(), } } } #[derive(Deserialize, Debug)] struct Extension { ilmd: Ilmd } impl Default for Extension { fn default() -> Self { Extension { ilmd: Ilmd { lot_number: "".to_string(), item_expiration_date: "".to_string(), } } } } #[derive(Deserialize, Debug)] struct Id { #[serde(rename = "$value")] element_content: String } #[derive(Deserialize, Debug)] struct ReadPoint { id: Id } #[derive(Deserialize, Debug)] struct BizLocation { id: Id } |
The main.rs Codes
All the aforementioned structs should appear before the main function. The codes below read the XML file using BufRead for performance reasons. They also pass the reader object to the from_reader function to perform the actual deserialization.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #[macro_use] extern crate serde_derive; extern crate serde; extern crate serde_xml_rs; use std::io::BufReader; use std::fs::File; use serde_xml_rs::{from_reader}; use serde::export::Default; // Start - EPCIS 1.2 struts // *** // *** Place all struts here // *** // End - EPCIS 1.2 struts fn main() { let f = File::open("sample-epcis1.2-xml.xml").expect("Unable to open"); let reader = BufReader::new(f); let epcis: EPCISDocument = from_reader(reader).unwrap(); println!("{:#?}", epcis); } |
The codes also use the Debug trait to display the content of a struct using println!
Output
As shown below, the codes read the EPCIS XML into the struct instance of EPCISDocument.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | C:/Users/karldev/.cargo/bin/cargo.exe run --color=always --package xml-rs-read-xml --bin xml-rs-read-xml Compiling xml-rs-read-xml v0.1.0 (C:\Users\karldev\Desktop\dev\blogs\rust\xml-rs-read-xml) Finished dev [unoptimized + debuginfo] target(s) in 2.76s Running `target\debug\xml-rs-read-xml.exe` EPCISDocument { epcis_header: EPCISHeader { standard_business_document_header: StandardBusinessDocumentHeader { header_version: "1.0", sender: SenderIdentifier { identifier: SenderReceiverIdentifier { authority: "GLN", element_content: "00000000", }, }, receiver: ReceiverIdentifier { identifier: SenderReceiverIdentifier { authority: "GLN", element_content: "11111111", }, }, ... |
The complete console output is available as output.txt.