Skip to content

WIP: Implement a bit of support for xsl:param and xsl:call-template#123

Closed
bojidar-bg wants to merge 8 commits intoPaligo:mainfrom
bojidar-bg:x-xee-param
Closed

WIP: Implement a bit of support for xsl:param and xsl:call-template#123
bojidar-bg wants to merge 8 commits intoPaligo:mainfrom
bojidar-bg:x-xee-param

Conversation

@bojidar-bg
Copy link
Contributor

@bojidar-bg bojidar-bg commented Sep 25, 2025

This is a draft, just wanted to share my work experimenting with xsl:param and xsl:with-param in relation to apply-templates. In addition, I decided to have a go at getting a hack version of xsl:call-template in, just to see how many tests it might unfilter.

Design decisions taken so far:

  • xsl:param-s are members of a map, which is subsequently passed as the first last parameter to the internal function declared by xsl:template.
  • (WIP) To support passing through parameters in the built-in rules, a special parameter called HACKHACKPASSTHROUGH causes parameter pass-through. Will have to figure out a smarter way of figuring out which apply-templates calls should pass their parameters through, but wanted to see how many tests are impacted by that first. (Answer: 4 tests)
  • (WIP) To support calling named templates through xsl:call-template, all named templates are registered as brand new modes with an empty predicate pattern, and then executed with some arbitrary context item (here, an empty string). Will have to figure out a better place to store the list of named templates, but wanted to see how many tests are impacted by that first. (Answer: A whooping 32 36 tests)
  • (WIP) To support xsl:param-s at the root level, the main function also takes a list of parameters, like all the functions declared by xsl:template. It currently does not mark them as global (due to the lack of tunnelling or global parameters in general), which means they end up disappearing within a few templates, but again, testing how many tests depend on some very basic support for this. (Answer: 5 tests, the rest also need xsl:variable)

copy-0801
copy-0901
copy-1001
copy-1002
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will have to investigate that one...

Copy link
Contributor Author

@bojidar-bg bojidar-bg Sep 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually—broken in main too!
Investigating a bit, seems like in XSLT, "For backwards compatibility reasons, the pattern node(), when used without an explicit axis, does not match document nodes, attribute nodes, or namespace nodes." (ref), but Xee implement node() the same as in XPath, where it can match absolutely anything.

Something similar seems to be occurring in copy-4502, where match="*" manages to match the document node again.

conflict-resolution-0801
conflict-resolution-0802
conflict-resolution-1001
conflict-resolution-1101
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of a few tests that exercise exactly what is implemented here 😅

pub struct ApplyTemplates {
pub mode: ApplyTemplatesModeValue,
pub select: AtomS,
pub named_params: AtomS,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ought to be TemplateNames.

})
}

fn sequence_constructor_function(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wohoo code duplication!

Unfoturnatelly, due to design decision 1, named xsl:param-s are now part of the argument list of sequence_constructor_function-s, so the main function can no longer be a sequence_constructor_function.

}

let parent_var_name = self.variables.current_template_names();
let (named_params_atom, bindings) = if pass_all_named && parent_var_name.is_some() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(No clue why parent_var_name.is_some() is needed, as noted around here, // HACK)

@bojidar-bg bojidar-bg changed the title WIP: Implement a bit more support for xsl:param WIP: Implement a bit of support for xsl:param and xsl:call-template Sep 26, 2025
@bojidar-bg
Copy link
Contributor Author

I feel this draft PR ended up covering too much ground at once, so I'll probably end up closing it, then reimplementing parts of the functionality (global param/variable/function declarations, then named templates, then template params) afresh, now that I have a better idea of where the nasty parts are.

@faassen On the topic of global params (and also variables/functions), I'm trying to wrap my head around the best way to implement those. I keep going back and forth between two general ideas:

  1. Reintroduce global_variables to xee_interpreter::declaration::Declarations, that was previously removed in 64dc462, then work on implementing support for it through new opcodes in the interpreter. (dyn Fn(Box<dyn Fn...>)) tho 😂)
  2. Remove declarations from the xee_interpreter::interpreter::Program and completely revamp the ApplyTemplates / declaration_compiler system so that templates (along with their patterns and bodies) can be registered at interpretation time as Closure-s.

The main benefit of 1 is that we get to keep the existing code as-is. The main downside is that every single declaration-supplied feature will end up impacting the interpreter and widening the rift between XSLT and XPath.
The main benefit of 2 is that XSLT can use regular IR features for the root level / main sequence function, and access variables defined in that main sequence function in the other functions, through regular IR closures.

Implementing more of XSLT in terms of the IR, as 2 would imply, feels like it would lead to a more elegant codebase overall; but having major parts of XSLT implemented in Rust probably means a simpler-to-understand codebase.

Thoughts?

@bojidar-bg
Copy link
Contributor Author

bojidar-bg commented Oct 27, 2025

Closing. This draft PR has served it's purpose for now -- helping me figure out what the hard parts of supporting Params are going to be.

@bojidar-bg bojidar-bg closed this Oct 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant