apisdk/extractor/
xml.rs

1use std::any::TypeId;
2
3use serde::de::DeserializeOwned;
4use serde_json::Value;
5
6use crate::{ApiError, ApiResult, MimeType, ResponseBody};
7
8/// This struct is used to parse response body to xml
9#[derive(Debug)]
10pub struct Xml;
11
12impl Xml {
13    fn do_try_parse<T>(text: String) -> ApiResult<T>
14    where
15        T: 'static + DeserializeOwned,
16    {
17        let type_id = TypeId::of::<T>();
18        if type_id == TypeId::of::<()>() {
19            serde_json::from_value(Value::Null).map_err(|_| ApiError::Impossible)
20        } else if type_id == TypeId::of::<String>() {
21            let value = serde_json::Value::String(text);
22            serde_json::from_value(value).map_err(|_| ApiError::Impossible)
23        } else {
24            quick_xml::de::from_str(&text).map_err(ApiError::DecodeXml)
25        }
26    }
27
28    /// Try to parse response
29    pub fn try_parse<T>(body: ResponseBody) -> ApiResult<T>
30    where
31        T: 'static + DeserializeOwned,
32    {
33        let type_id = TypeId::of::<T>();
34        if type_id == TypeId::of::<()>() {
35            return serde_json::from_value(Value::Null).map_err(|_| ApiError::Impossible);
36        }
37
38        match body {
39            ResponseBody::Xml(xml) => Self::do_try_parse(xml),
40            ResponseBody::Text(text) => {
41                log::debug!("Treat text as xml for decoding");
42                Self::do_try_parse(text)
43            }
44            _ => Err(ApiError::IncompatibleContentType(
45                MimeType::Xml,
46                body.mime_type(),
47            )),
48        }
49    }
50}