#![cfg(feature = "xsd")]
use sup_xml_core::{parse_str, ParseOptions};
use sup_xml_xslt::loader::InMemoryLoader;
use sup_xml_xslt::Stylesheet;
const SCHEMA: &str = r#"<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="urn:test"
xmlns="urn:test"
elementFormDefault="qualified">
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element name="n" type="xs:integer"/>
<xs:element name="s" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>"#;
#[test]
fn data_of_schema_typed_source_node_is_typed() {
let xsl = r#"<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:import-schema namespace="urn:test" schema-location="test.xsd"/>
<xsl:template match="/">
<out canonical="{data(/*/*[1])}"
is-integer="{data(/*/*[1]) instance of xs:integer}"
is-string="{data(/*/*[1]) instance of xs:string}"/>
</xsl:template>
</xsl:stylesheet>"#;
let loader = InMemoryLoader::new().with("test.xsd", SCHEMA);
let style = Stylesheet::compile_str_with_loader(xsl, &loader, None)
.expect("stylesheet with import-schema should compile");
let mut opts = ParseOptions::default();
opts.namespace_aware = true;
let src = parse_str(
r#"<root xmlns="urn:test"><n>042</n><s>hi</s></root>"#, &opts,
).unwrap();
let out = style.apply_with_loader(&src, &loader, None)
.expect("apply should succeed")
.to_string()
.unwrap();
assert!(out.contains(r#"canonical="42""#),
"typed integer should atomize to its canonical form, got: {out}");
assert!(out.contains(r#"is-integer="true""#),
"typed value should be an instance of xs:integer, got: {out}");
assert!(out.contains(r#"is-string="false""#),
"an xs:integer-typed value is NOT an instance of xs:string, got: {out}");
}
#[test]
fn data_of_constructed_typed_element_is_typed() {
let xsl = r#"<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:variable name="t"><e xsl:type="xs:integer">003</e></xsl:variable>
<xsl:template match="/">
<out canonical="{data($t/e)}"
is-int="{data($t/e) instance of xs:integer}"
is-str="{data($t/e) instance of xs:string}"/>
</xsl:template>
</xsl:stylesheet>"#;
let style = Stylesheet::compile_str(xsl).expect("compile");
let mut opts = ParseOptions::default();
opts.namespace_aware = true;
let src = parse_str("<doc/>", &opts).unwrap();
let out = style.apply(&src).expect("apply").to_string().unwrap();
assert!(out.contains(r#"canonical="3""#),
"constructed xs:integer should atomize to canonical '3', got: {out}");
assert!(out.contains(r#"is-int="true""#),
"constructed xs:integer-typed value is an instance of xs:integer, got: {out}");
assert!(out.contains(r#"is-str="false""#),
"constructed xs:integer is NOT an instance of xs:string, got: {out}");
}
#[test]
fn data_of_constructed_typed_attribute_is_typed() {
let xsl = r#"<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:variable name="t">
<e><xsl:attribute name="n" type="xs:integer">003</xsl:attribute></e>
</xsl:variable>
<xsl:template match="/">
<out canonical="{data($t/e/@n)}"
is-int="{data($t/e/@n) instance of xs:integer}"
is-str="{data($t/e/@n) instance of xs:string}"/>
</xsl:template>
</xsl:stylesheet>"#;
let style = Stylesheet::compile_str(xsl).expect("compile");
let mut opts = ParseOptions::default();
opts.namespace_aware = true;
let src = parse_str("<doc/>", &opts).unwrap();
let out = style.apply(&src).expect("apply").to_string().unwrap();
assert!(out.contains(r#"canonical="3""#),
"constructed typed attribute should atomize to canonical '3', got: {out}");
assert!(out.contains(r#"is-int="true""#),
"constructed xs:integer attribute is an instance of xs:integer, got: {out}");
assert!(out.contains(r#"is-str="false""#),
"constructed xs:integer attribute is NOT an instance of xs:string, got: {out}");
}
#[test]
fn number_of_function_item_errors() {
let xsl = r#"<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:local="http://local/">
<xsl:function name="local:f" as="xs:integer"><xsl:param name="x" as="xs:integer"/>
<xsl:sequence select="$x + 1"/></xsl:function>
<xsl:template match="/"><out><xsl:value-of select="number(local:f#1)"/></out></xsl:template>
</xsl:stylesheet>"#;
let style = Stylesheet::compile_str(xsl).expect("compile");
let mut opts = ParseOptions::default(); opts.namespace_aware = true;
let src = parse_str("<doc/>", &opts).unwrap();
assert!(style.apply(&src).is_err(), "number() of a function item must error (FOTY0013)");
}
#[test]
fn untyped_atomic_arithmetic_is_double() {
let xsl = r#"<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:template match="/"><out><xsl:value-of select="xs:untypedAtomic('123.456') + 1"/></out></xsl:template>
</xsl:stylesheet>"#;
let style = Stylesheet::compile_str(xsl).expect("compile");
let mut opts = ParseOptions::default(); opts.namespace_aware = true;
let src = parse_str("<doc/>", &opts).unwrap();
let out = style.apply(&src).unwrap().to_string().unwrap();
assert!(out.contains("124.456"), "untypedAtomic+int must be xs:double (124.456), got: {out}");
}
#[test]
fn xsl_text_expand_text_tvt() {
let xsl = r#"<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/"><out>
<xsl:variable name="x" select="42"/>
<xsl:text expand-text="yes">value={$x}!</xsl:text>
</out></xsl:template></xsl:stylesheet>"#;
let style = Stylesheet::compile_str(xsl).expect("compile");
let mut o = ParseOptions::default(); o.namespace_aware = true;
let src = parse_str("<d/>", &o).unwrap();
let out = style.apply(&src).unwrap().to_string().unwrap();
assert!(out.contains("value=42!"), "expand-text TVT in xsl:text should expand {{$x}}, got: {out}");
}