use libxml::parser::Parser;
use libxml::tree::c14n::{CanonicalizationMode, CanonicalizationOptions};
fn assert_eq_lines(seen: &str, expected: &str) {
let lines_iter = seen.lines().zip(expected.lines());
for (seen_line, expected_line) in lines_iter {
assert_eq!(seen_line, expected_line);
}
assert_eq!(seen.lines().count(), expected.lines().count());
}
fn canonicalize_xml(input: &str, opts: CanonicalizationOptions) -> String {
let parser = Parser::default();
let doc = parser.parse_string(input).unwrap();
doc.canonicalize(opts, None).unwrap()
}
#[test]
fn canonical_1_1_example_3_1_no_comment() {
let input = include_str!("resources/canonical_1_1/3_1_input.xml");
let expected = include_str!("resources/canonical_1_1/3_1_output_no_comment.xml");
let canonicalized = canonicalize_xml(
input,
CanonicalizationOptions {
mode: CanonicalizationMode::Canonical1_1,
with_comments: false,
inclusive_ns_prefixes: vec![],
},
);
assert_eq_lines(&canonicalized, expected);
}
#[test]
fn canonical_1_1_example_3_2() {
let input = include_str!("resources/canonical_1_1/3_2_input.xml");
let expected = include_str!("resources/canonical_1_1/3_2_output.xml");
let canonicalized = canonicalize_xml(
input,
CanonicalizationOptions {
mode: CanonicalizationMode::Canonical1_1,
with_comments: true,
inclusive_ns_prefixes: vec![],
},
);
assert_eq_lines(&canonicalized, expected.trim())
}
#[test]
fn canonical_exclusive_example_1() {
let input = include_str!("resources/canonical_exclusive/1_input.xml");
let expected = include_str!("resources/canonical_exclusive/1_output.xml");
let canonicalized = canonicalize_xml(
input,
CanonicalizationOptions {
mode: CanonicalizationMode::ExclusiveCanonical1_0,
with_comments: true,
inclusive_ns_prefixes: vec![],
},
);
assert_eq_lines(&canonicalized, expected.trim())
}
#[test]
fn canonical_exclusive_example_2() {
let input = include_str!("resources/canonical_exclusive/2_input.xml");
let expected = include_str!("resources/canonical_exclusive/2_output.xml");
let canonicalized = canonicalize_xml(
input,
CanonicalizationOptions {
mode: CanonicalizationMode::ExclusiveCanonical1_0,
with_comments: true,
inclusive_ns_prefixes: ["stay1".to_string(), "stay2".to_string()].to_vec(),
},
);
assert_eq_lines(&canonicalized, expected.trim())
}
#[test]
fn test_c14n_node() {
let xml = "<a><b><c></c></b></a>";
let doc = Parser::default().parse_string(xml).unwrap();
let mut node = doc.as_node().findnodes("//b").unwrap().pop().unwrap();
let c14n = node.canonicalize(opts()).unwrap();
assert_eq!("<b><c></c></b>", c14n)
}
#[test]
fn test_c14n_modes() {
let doc1 = Parser::default()
.parse_string(
r#"
<n0:local xmlns:n0="http://foobar.org" xmlns:n3="ftp://example.org">
<n1:elem2 xmlns:n1="http://example.net" xml:lang="en">
<n3:stuff xmlns:n3="ftp://example.org"/>
</n1:elem2>
</n0:local>
"#,
)
.unwrap();
let mut node1 = doc1
.as_node()
.at_xpath("//n1:elem2", &[("n1", "http://example.net")])
.unwrap()
.unwrap();
let doc2 = Parser::default()
.parse_string(
r#"
<n2:pdu xmlns:n1="http://example.com"
xmlns:n2="http://foo.example"
xmlns:n4="http://foo.example"
xml:lang="fr"
xml:space="retain">
<n1:elem2 xmlns:n1="http://example.net" xml:lang="en">
<n3:stuff xmlns:n3="ftp://example.org"/>
<n4:stuff />
</n1:elem2>
</n2:pdu>
"#,
)
.unwrap();
let mut node2 = doc2
.as_node()
.at_xpath("//n1:elem2", &[("n1", "http://example.net")])
.unwrap()
.unwrap();
let expected = r#"
<n1:elem2 xmlns:n0="http://foobar.org" xmlns:n1="http://example.net" xmlns:n3="ftp://example.org" xml:lang="en">
<n3:stuff></n3:stuff>
</n1:elem2>
"#.trim();
let c14n = node1.canonicalize(opts()).unwrap();
assert_eq_lines(expected, &c14n);
let expected = r#"
<n1:elem2 xmlns:n1="http://example.net" xmlns:n2="http://foo.example" xmlns:n4="http://foo.example" xml:lang="en" xml:space="retain">
<n3:stuff xmlns:n3="ftp://example.org"></n3:stuff>
<n4:stuff></n4:stuff>
</n1:elem2>
"#.trim();
let c14n = node2.canonicalize(opts()).unwrap();
assert_eq_lines(&expected, &c14n);
let opts = CanonicalizationOptions {
mode: CanonicalizationMode::Canonical1_0,
..Default::default()
};
let c14n = node2.canonicalize(opts).unwrap();
assert_eq_lines(expected, &c14n);
let expected = r#"
<n1:elem2 xmlns:n1="http://example.net" xml:lang="en">
<n3:stuff xmlns:n3="ftp://example.org"></n3:stuff>
</n1:elem2>
"#
.trim();
let c14n = node1
.canonicalize(CanonicalizationOptions {
mode: CanonicalizationMode::ExclusiveCanonical1_0,
..Default::default()
})
.unwrap();
assert_eq_lines(expected, &c14n);
let expected = r#"
<n1:elem2 xmlns:n1="http://example.net" xml:lang="en">
<n3:stuff xmlns:n3="ftp://example.org"></n3:stuff>
<n4:stuff xmlns:n4="http://foo.example"></n4:stuff>
</n1:elem2>
"#
.trim();
let c14n = node2
.canonicalize(CanonicalizationOptions {
mode: CanonicalizationMode::ExclusiveCanonical1_0,
..Default::default()
})
.unwrap();
assert_eq_lines(expected, &c14n);
let expected = r#"
<n1:elem2 xmlns:n1="http://example.net" xmlns:n2="http://foo.example" xml:lang="en">
<n3:stuff xmlns:n3="ftp://example.org"></n3:stuff>
<n4:stuff xmlns:n4="http://foo.example"></n4:stuff>
</n1:elem2>
"#
.trim();
let c14n = node2
.canonicalize(CanonicalizationOptions {
mode: CanonicalizationMode::ExclusiveCanonical1_0,
inclusive_ns_prefixes: vec!["n2".into()],
..Default::default()
})
.unwrap();
assert_eq_lines(expected, &c14n);
let expected = r#"
<n1:elem2 xmlns:n1="http://example.net" xmlns:n2="http://foo.example" xmlns:n4="http://foo.example" xml:lang="en">
<n3:stuff xmlns:n3="ftp://example.org"></n3:stuff>
<n4:stuff></n4:stuff>
</n1:elem2>
"#.trim();
let c14n = node2
.canonicalize(CanonicalizationOptions {
mode: CanonicalizationMode::ExclusiveCanonical1_0,
inclusive_ns_prefixes: vec!["n2".into(), "n4".into()],
..Default::default()
})
.unwrap();
assert_eq_lines(expected, &c14n);
let expected = r#"
<n1:elem2 xmlns:n1="http://example.net" xmlns:n2="http://foo.example" xmlns:n4="http://foo.example" xml:lang="en" xml:space="retain">
<n3:stuff xmlns:n3="ftp://example.org"></n3:stuff>
<n4:stuff></n4:stuff>
</n1:elem2>
"#.trim();
let c14n = node2
.canonicalize(CanonicalizationOptions {
mode: CanonicalizationMode::Canonical1_1,
..Default::default()
})
.unwrap();
assert_eq_lines(expected, &c14n);
}
fn opts() -> CanonicalizationOptions {
CanonicalizationOptions {
mode: CanonicalizationMode::Canonical1_1,
with_comments: false,
inclusive_ns_prefixes: vec![],
}
}