Skip to main content

rs_xml2selected/
lib.rs

1use std::io;
2
3use io::BufWriter;
4use io::Write;
5
6use io::Read;
7
8use sxd_document::Package;
9use sxd_document::dom::Document;
10
11use sxd_xpath::Value;
12
13pub struct XmlElement(pub Package);
14
15impl XmlElement {
16    pub fn str2xml(xml: &str) -> Result<Self, io::Error> {
17        let pkg: Package = sxd_document::parser::parse(xml).map_err(io::Error::other)?;
18        Ok(Self(pkg))
19    }
20}
21
22impl XmlElement {
23    pub fn as_document(&self) -> Document<'_> {
24        self.0.as_document()
25    }
26}
27
28pub fn select_value<'a>(doc: &'a Document<'a>, xpath: &str) -> Result<Value<'a>, io::Error> {
29    sxd_xpath::evaluate_xpath(doc, xpath).map_err(io::Error::other)
30}
31
32impl XmlElement {
33    pub fn xpath2bool(&self, xpath: &str) -> Result<bool, io::Error> {
34        let doc: Document = self.as_document();
35        let val: Value = select_value(&doc, xpath)?;
36        match val {
37            Value::Boolean(b) => Ok(b),
38            Value::Number(f) => Err(io::Error::other(format!("not a bool: {f}"))),
39            Value::String(s) => Err(io::Error::other(format!("not a bool: {s}"))),
40            Value::Nodeset(_) => Err(io::Error::other("node set got")),
41        }
42    }
43
44    pub fn xpath2number(&self, xpath: &str) -> Result<f64, io::Error> {
45        let doc: Document = self.as_document();
46        let val: Value = select_value(&doc, xpath)?;
47        match val {
48            Value::Boolean(b) => Err(io::Error::other(format!("not a number: {b}"))),
49            Value::Number(f) => Ok(f),
50            Value::String(s) => Err(io::Error::other(format!("not a number: {s}"))),
51            Value::Nodeset(_) => Err(io::Error::other("node set got")),
52        }
53    }
54
55    pub fn xpath2string(&self, xpath: &str) -> Result<String, io::Error> {
56        let doc: Document = self.as_document();
57        let val: Value = select_value(&doc, xpath)?;
58        match val {
59            Value::Boolean(b) => Err(io::Error::other(format!("not a string: {b}"))),
60            Value::Number(f) => Err(io::Error::other(format!("not a string: {f}"))),
61            Value::String(s) => Ok(s),
62            Value::Nodeset(_) => Err(io::Error::other("node set got")),
63        }
64    }
65}
66
67impl XmlElement {
68    pub fn xpath2print<W>(&self, xpath: &str, mut wtr: W) -> Result<(), io::Error>
69    where
70        W: Write,
71    {
72        let doc: Document = self.as_document();
73        let val: Value = select_value(&doc, xpath)?;
74        match val {
75            Value::Boolean(b) => writeln!(&mut wtr, "{b}"),
76            Value::Number(f) => writeln!(&mut wtr, "{f}"),
77            Value::String(s) => writeln!(&mut wtr, "{s}"),
78            Value::Nodeset(n) => writeln!(&mut wtr, "{n:?}"),
79        }?;
80        wtr.flush()
81    }
82
83    pub fn xpath2stdout(&self, xpath: &str) -> Result<(), io::Error> {
84        let o = io::stdout();
85        let mut ol = o.lock();
86        self.xpath2print(xpath, BufWriter::new(&mut ol))?;
87        ol.flush()
88    }
89}
90
91pub fn str2xml2xpath2stdout(xml: &str, xpath: &str) -> Result<(), io::Error> {
92    let xe: XmlElement = XmlElement::str2xml(xml)?;
93    xe.xpath2stdout(xpath)
94}
95
96pub const XML_SIZE_LIMIT_DEFAULT: u64 = 16777216;
97
98pub fn stdin2xml2xpath2stdout(limit: u64, xpath: &str) -> Result<(), io::Error> {
99    let i = io::stdin().lock();
100    let mut limited = i.take(limit);
101    let mut buf: Vec<u8> = vec![];
102    limited.read_to_end(&mut buf)?;
103    let s: &str = std::str::from_utf8(&buf).map_err(io::Error::other)?;
104    str2xml2xpath2stdout(s, xpath)
105}