xsl:variable is not defined in predicate - xslt

It looks like the xsl:variables are not defined in the predicates in libxml2.
Is it possible or I miss something ? If I use the variable out of the predicate, then its fine.
<xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" />
<xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
<xsl:template match="*[translate( name(), $uppercase, $smallcase ) = 'receipt']">
<xsl:apply-templates select="Process"/>
<xsl:apply-templates select="Encode"/>
</xsl:template>

Yes in XSLT 1.0, you cannot use variables inside the match attribute but I believe in XSLT 2.0 you can.
Maybe you can do something like this instead: (note that this may not work for you as-is, it depends on how the rest of your XSL is written)
<xsl:template match="*">
<xsl:choose>
<xsl:when test="translate( name(.), $uppercase, $smallcase ) = 'receipt'">
<xsl:apply-templates select="Process"/>
<xsl:apply-templates select="Encode"/>
</xsl:when>
<xsl:otherwise>
<!-- do whatever else should be done -->
</xsl:otherwise>
</xsl:choose>
</xsl:template>

Related

Schematron Using Include Fails With Ambiguous rule match

I am running the core schematron XSLT (as downloaded from http://schematron.com/front-page/the-schematron-skeleton-implementation/) against my schematron rules which have an include statement. When trying to run the XML instance to be tested through the intermediate XSL, it fails with 'Ambiguous rule match for' for each rule present in the included schematron.
"Description: Ambiguous rule match for
/filing:FilingMessage/filing:FilingConnectedDocument[1]/ecf:DocumentAugmentation[1]/ecf:DocumentRendition[1]/nc:Attachment[1]/nc:BinaryFormatText[1]
Matches both
"{http://release.niem.gov/niem/niem-core/3.0/}BinaryFormatText" on line 192 of file:/C:/_working/misc/schematron/schematron/trunk/schematron/code/temp.xsl
and
"{http://release.niem.gov/niem/niem-core/3.0/}BinaryFormatText" on line 175 of file:/C:/_working/misc/schematron/schematron/trunk/schematron/code/temp.xsl
URL: http://www.w3.org/TR/xslt20/#err-XTRE0540".
Upon inspecting the resulting intermediate XSL, it appears that the rules contained in the included schematron file are rendered into the intermediate XSL twice. Inspecting the XSL file iso_schematron_skeleton_for_saxon.xsl, it looks like the iso:include calls the rules template with both the pattern node and the rules node which results in the duplication of the data.
I would have assumed that the schematron XSLT on github is the definitive implementation of the schematron specification. Is that not the case or can anyone comment to this as I don't feel it is correct for me to have to tweak the schematron XSLT to make it work?
Base Schematron
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2">
<title>Test Schematron Illustrating Transform Bug</title>
<ns prefix="x" uri="http://www.w3.org/TR/REC-html40"/>
<ns prefix="filing" uri="https://docs.oasis-open.org/legalxml-courtfiling/ns/v5.0/filing"/>
<ns prefix="nc" uri="http://release.niem.gov/niem/niem-core/3.0/"/>
<include href="ExternalTestPattern.sch"/>
<pattern id="ecf">
<rule context="/filing:FilingMessage">
<assert test="./nc:DocumentIdentification/nc:IdentificationID">DocumentID must be present.</assert>
</rule>
</pattern>
</schema>
ExternalTestPattern.sch Schematron
<?xml version="1.0" encoding="UTF-8"?>
<pattern xmlns="http://purl.oclc.org/dsdl/schematron" id="code-list-rules">
<!-- Required namespace declarations as indicated in this set of rules:
<ns prefix="nc" uri="http://release.niem.gov/niem/niem-core/3.0/"/> -->
<rule context="nc:BinaryFormatText">
<assert test="( false() or ( contains('application/jsonapplication/mswordapplication/pdfapplication/vnd.oasis.opendocument.textapplication/vnd.openxmlformats-officedocument.wordprocessingml.documentapplication/xml',concat('',.,'')) ) ) ">Invalid binary format code value.</assert>
</rule>
</pattern>
One other thing I forgot to mention is that if I simply use an XML editor like Oxygen or XML buddy to use my schematron to validate the XML instance, it works fine.
When I use Oxygen to load my Test.sch and also iso_schematron_message_xslt2.xslt, the resulting XSLT is below. Partway down you will see that the template for the rule defined in ExternalTestPattern.sch (match="nc:BinaryFormatText") is duplicated:
<xsl:stylesheet xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:saxon="http://saxon.sf.net/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:schold="http://www.ascc.net/xml/schematron" xmlns:iso="http://purl.oclc.org/dsdl/schematron" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:x="http://www.w3.org/TR/REC-html40" xmlns:filing="https://docs.oasis-open.org/legalxml-courtfiling/ns/v5.0/filing" xmlns:nc="http://release.niem.gov/niem/niem-core/3.0/" version="2.0">
<!--Implementers: please note that overriding process-prolog or process-root is the preferred method for meta-stylesheets to use where possible. -->
<xsl:param name="archiveDirParameter"/>
<xsl:param name="archiveNameParameter"/>
<xsl:param name="fileNameParameter"/>
<xsl:param name="fileDirParameter"/>
<xsl:variable name="document-uri">
<xsl:value-of select="document-uri(/)"/>
</xsl:variable>
<!--PHASES-->
<!--PROLOG-->
<xsl:output method="text"/>
<!--XSD TYPES FOR XSLT2-->
<!--KEYS AND FUNCTIONS-->
<!--DEFAULT RULES-->
<!--MODE: SCHEMATRON-SELECT-FULL-PATH-->
<!--This mode can be used to generate an ugly though full XPath for locators-->
<xsl:template match="*" mode="schematron-select-full-path">
<xsl:apply-templates select="." mode="schematron-get-full-path"/>
</xsl:template>
<!--MODE: SCHEMATRON-FULL-PATH-->
<!--This mode can be used to generate an ugly though full XPath for locators-->
<xsl:template match="*" mode="schematron-get-full-path">
<xsl:apply-templates select="parent::*" mode="schematron-get-full-path"/>
<xsl:text>/</xsl:text>
<xsl:choose>
<xsl:when test="namespace-uri()=''">
<xsl:value-of select="name()"/>
</xsl:when>
<xsl:otherwise>
<xsl:text>*:</xsl:text>
<xsl:value-of select="local-name()"/>
<xsl:text>[namespace-uri()='</xsl:text>
<xsl:value-of select="namespace-uri()"/>
<xsl:text>']</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:variable name="preceding" select="count(preceding-sibling::*[local-name()=local-name(current()) and namespace-uri() = namespace-uri(current())])"/>
<xsl:text>[</xsl:text>
<xsl:value-of select="1+ $preceding"/>
<xsl:text>]</xsl:text>
</xsl:template>
<xsl:template match="#*" mode="schematron-get-full-path">
<xsl:apply-templates select="parent::*" mode="schematron-get-full-path"/>
<xsl:text>/</xsl:text>
<xsl:choose>
<xsl:when test="namespace-uri()=''">#<xsl:value-of select="name()"/>
</xsl:when>
<xsl:otherwise>
<xsl:text>#*[local-name()='</xsl:text>
<xsl:value-of select="local-name()"/>
<xsl:text>' and namespace-uri()='</xsl:text>
<xsl:value-of select="namespace-uri()"/>
<xsl:text>']</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!--MODE: SCHEMATRON-FULL-PATH-2-->
<!--This mode can be used to generate prefixed XPath for humans-->
<xsl:template match="node() | #*" mode="schematron-get-full-path-2">
<xsl:for-each select="ancestor-or-self::*">
<xsl:text>/</xsl:text>
<xsl:value-of select="name(.)"/>
<xsl:if test="preceding-sibling::*[name(.)=name(current())]">
<xsl:text>[</xsl:text>
<xsl:value-of select="count(preceding-sibling::*[name(.)=name(current())])+1"/>
<xsl:text>]</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:if test="not(self::*)">
<xsl:text/>/#<xsl:value-of select="name(.)"/>
</xsl:if>
</xsl:template>
<!--MODE: SCHEMATRON-FULL-PATH-3-->
<!--This mode can be used to generate prefixed XPath for humans
(Top-level element has index)-->
<xsl:template match="node() | #*" mode="schematron-get-full-path-3">
<xsl:for-each select="ancestor-or-self::*">
<xsl:text>/</xsl:text>
<xsl:value-of select="name(.)"/>
<xsl:if test="parent::*">
<xsl:text>[</xsl:text>
<xsl:value-of select="count(preceding-sibling::*[name(.)=name(current())])+1"/>
<xsl:text>]</xsl:text>
</xsl:if>
</xsl:for-each>
<xsl:if test="not(self::*)">
<xsl:text/>/#<xsl:value-of select="name(.)"/>
</xsl:if>
</xsl:template>
<!--MODE: GENERATE-ID-FROM-PATH -->
<xsl:template match="/" mode="generate-id-from-path"/>
<xsl:template match="text()" mode="generate-id-from-path">
<xsl:apply-templates select="parent::*" mode="generate-id-from-path"/>
<xsl:value-of select="concat('.text-', 1+count(preceding-sibling::text()), '-')"/>
</xsl:template>
<xsl:template match="comment()" mode="generate-id-from-path">
<xsl:apply-templates select="parent::*" mode="generate-id-from-path"/>
<xsl:value-of select="concat('.comment-', 1+count(preceding-sibling::comment()), '-')"/>
</xsl:template>
<xsl:template match="processing-instruction()" mode="generate-id-from-path">
<xsl:apply-templates select="parent::*" mode="generate-id-from-path"/>
<xsl:value-of select="concat('.processing-instruction-', 1+count(preceding-sibling::processing-instruction()), '-')"/>
</xsl:template>
<xsl:template match="#*" mode="generate-id-from-path">
<xsl:apply-templates select="parent::*" mode="generate-id-from-path"/>
<xsl:value-of select="concat('.#', name())"/>
</xsl:template>
<xsl:template match="*" mode="generate-id-from-path" priority="-0.5">
<xsl:apply-templates select="parent::*" mode="generate-id-from-path"/>
<xsl:text>.</xsl:text>
<xsl:value-of select="concat('.',name(),'-',1+count(preceding-sibling::*[name()=name(current())]),'-')"/>
</xsl:template>
<!--MODE: GENERATE-ID-2 -->
<xsl:template match="/" mode="generate-id-2">U</xsl:template>
<xsl:template match="*" mode="generate-id-2" priority="2">
<xsl:text>U</xsl:text>
<xsl:number level="multiple" count="*"/>
</xsl:template>
<xsl:template match="node()" mode="generate-id-2">
<xsl:text>U.</xsl:text>
<xsl:number level="multiple" count="*"/>
<xsl:text>n</xsl:text>
<xsl:number count="node()"/>
</xsl:template>
<xsl:template match="#*" mode="generate-id-2">
<xsl:text>U.</xsl:text>
<xsl:number level="multiple" count="*"/>
<xsl:text>_</xsl:text>
<xsl:value-of select="string-length(local-name(.))"/>
<xsl:text>_</xsl:text>
<xsl:value-of select="translate(name(),':','.')"/>
</xsl:template>
<!--Strip characters--><xsl:template match="text()" priority="-1"/>
<!--SCHEMA SETUP-->
<xsl:template match="/">
<xsl:apply-templates select="/" mode="M0"/>
<xsl:apply-templates select="/" mode="M5"/>
</xsl:template>
<!--SCHEMATRON PATTERNS-->
<!--PATTERN code-list-rules-->
<!--RULE -->
<xsl:template match="nc:BinaryFormatText" priority="1000" mode="M0">
<!--ASSERT -->
<xsl:choose>
<xsl:when test="( false() or ( contains('application/jsonapplication/mswordapplication/pdfapplication/vnd.oasis.opendocument.textapplication/vnd.openxmlformats-officedocument.wordprocessingml.documentapplication/xml',concat('',.,'')) ) ) "/>
<xsl:otherwise>
<xsl:message>Invalid binary format code value. (( false() or ( contains('application/jsonapplication/mswordapplication/pdfapplication/vnd.oasis.opendocument.textapplication/vnd.openxmlformats-officedocument.wordprocessingml.documentapplication/xml',concat('',.,'')) ) ))</xsl:message>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates select="*|comment()|processing-instruction()" mode="M0"/>
</xsl:template>
<xsl:template match="text()" priority="-1" mode="M0"/>
<xsl:template match="#*|node()" priority="-2" mode="M0">
<xsl:apply-templates select="*|comment()|processing-instruction()" mode="M0"/>
</xsl:template>
<!--RULE -->
<xsl:template match="nc:BinaryFormatText" priority="1000" mode="M0">
<!--ASSERT -->
<xsl:choose>
<xsl:when test="( false() or ( contains('application/jsonapplication/mswordapplication/pdfapplication/vnd.oasis.opendocument.textapplication/vnd.openxmlformats-officedocument.wordprocessingml.documentapplication/xml',concat('',.,'')) ) ) "/>
<xsl:otherwise>
<xsl:message>Invalid binary format code value. (( false() or ( contains('application/jsonapplication/mswordapplication/pdfapplication/vnd.oasis.opendocument.textapplication/vnd.openxmlformats-officedocument.wordprocessingml.documentapplication/xml',concat('',.,'')) ) ))</xsl:message>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates select="*|comment()|processing-instruction()" mode="M0"/>
</xsl:template>
<!--PATTERN ecf-->
<!--RULE -->
<xsl:template match="/filing:FilingMessage" priority="1000" mode="M5">
<!--ASSERT -->
<xsl:choose>
<xsl:when test="./nc:DocumentIdentification/nc:IdentificationID"/>
<xsl:otherwise>
<xsl:message>DocumentID must be present. (./nc:DocumentIdentification/nc:IdentificationID)</xsl:message>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates select="*|comment()|processing-instruction()" mode="M5"/>
</xsl:template>
<xsl:template match="text()" priority="-1" mode="M5"/>
<xsl:template match="#*|node()" priority="-2" mode="M5">
<xsl:apply-templates select="*|comment()|processing-instruction()" mode="M5"/>
</xsl:template>
</xsl:stylesheet>
Any enlightenment would be really helpful.
Thanks
Ensure that you are compiling the Schematron into XSLT by applying the sequence of transformations outlined in the readme, using the output of the prior XSLT transforms as the input to the next step:
1) First, preprocess your Schematron schema with iso_dsdl_include.xsl.
This is a macro processor to assemble the schema from various parts.
If your schema is not in separate parts, you can skip this stage. This
stage also generates error messages for some common XPath syntax
problems.
2) Second, preprocess the output from stage 1 with
iso_abstract_expand.xsl. This is a macro processor to convert
abstract patterns to real patterns. If your schema does not use
abstract patterns, you can skip this stage.
3) Third, compile the Schematron schema into an XSLT script. This
will typically use iso_svrl_for_xslt1.xsl or iso_svrl_for_xslt2.xsl
(which in turn invoke iso_schematron_skeleton_for_xslt1.xsl or
iso_schematron_skeleton_for_saxon.xsl) However, other
"meta-stylesheets" are also in common use; the principle of operation
is the same. If your schema uses Schematron phases, supply these as
command line/invocation parameters to this process.
4) Fourth, run the script generated by stage 3 against the document
being validated. If you are using the SVRL script, then the output of
validation will be an XML document. If your schema uses Schematron
parameters, supply these as command line/invocation parameters to this
process.
Also, ensure that you are applying iso_svrl_for_xslt2.xsl (which imports iso_schematron_skeleton_for_saxon.xsl) and are not using iso_schematron_skeleton_for_saxon.xsl directly

XSLT Expertise required duplicate values

Question edited, more information added
viv:tokenize=str:tokenize
viv:value-of=str:value-of
Part1 - Declaration and assigning value
<declare name="searchhistories" />
<set-var name="searchhistories">
<value-of select="concat(viv:value-of('searchquery','var'),'|',viv:replace(viv:value-of('searchhistory', 'var'),concat(viv:value-of('searchquery','var'),'\|'),'','g'))" />
</set-var>
Part 2: tokenize and de-duplicate
<xsl:for-each select="viv:tokenize($searchhistories,'|',false, false)">
<xsl:variable name="i" select="position()"/>
<xsl:if test="$i < 11">
<xsl:value-of select="." /> |
</xsl:if>
</xsl:for-each>
Able to tokenize but de-duplication not working
What should be code for de-duplication
<xsl:for-each select=***distinct-values***("viv:tokenize($searchhistories,'|',false, false)")>
Something like this ?
Try
<xsl:for-each select="set:distinct(viv:tokenize($searchhistories,'|',false, false))">
with the stylesheet declaring xmlns:set="http://exslt.org/sets" e.g.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:set="http://exslt.org/sets" exclude-result-prefixes="set">
The answer is based on the documentation you linked to in your comment, I am not able to test that.
But http://xsltransform.net/ej9EGcy uses the EXSLT version of tokenize and works fine:
<xsl:template match="item">
<xsl:copy>
<xsl:for-each select="set:distinct(str:tokenize(., '|'))">
<xsl:if test="position() > 1">|</xsl:if>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:copy>
</xsl:template>

How to make uppercase while doing <xsl:copy-of select="./*"/>

I have to make uppercase of all node values inside a parent node while copying the whole section.
For Example:
ATPM/37 zATP - Miscellaneous Exceptions Blank text box without number 1 Said
Change to:
ATPM/37 ZATP - MISCELLANEOUS EXCEPTIONS BLANK TEXT BOX WITHOUT NUMBER 1 SAID
In XSLT 2.0, try adding
<xsl:template match="text()">
<xsl:value-of select="upper-case(.)"/>
</xsl:template>
In XSLT 1.0, use
<xsl:template match="text()">
<xsl:value-of select="translate(., $smallcase, $uppercase)" />
</xsl:template>
<xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" />
<xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
instead
The xsl:copy-of instruction always does an exact copy; you can't use it to make a copy-with-changes. For that, use the identity template to copy things that you want to copy exactly, and a different template for things that you want to change. Thus:
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:value-of select="upper-case(.)"/>
</xsl:template>

How to show a character n times in XSLT?

I have a template with a parameter. How can I insert a tab character n times?
n is the value of the parameter.
In XSLT 2.0:
<xsl:for-each select="1 to $count"> </xsl:for-each>
(Sadly though, I suspect that if you were using XSLT 2.0 you wouldn't need to ask the question).
Another technique often used with XSLT 1.0 is the hack:
<xsl:for-each select="//*[position() <= $count]"> </xsl:for-each>
which works provided the number of elements in your source document is greater than the number of tab characters you want to output.
Just call it recursively; output a tab, then call the same template again with n-1 passed in, if n > 1.
<xsl:template name="repeat">
<xsl:param name="output" />
<xsl:param name="count" />
<xsl:if test="$count > 0">
<xsl:value-of select="$output" />
<xsl:call-template name="repeat">
<xsl:with-param name="output" select="$output" />
<xsl:with-param name="count" select="$count - 1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
As has been pointed out, this example will actually output a minimum of one. In my experience where the output is whitespace, it's usually needed. You can adapt the principle of a recursive template like this any way you see fit.
This seems the simplest and most flexible to me.
For XSLT 1.0 (or perhaps 1.1).
<xsl:variable name="count">10</xsl:variable>
<xsl:variable name="repeat"><xsl:text> </xsl:text></xsl:variable>
<xsl:sequence select="string-join((for $i in 1 to $count return $repeat),'')"/>
Of course the count variable is where you assign your n parameter.
I used the variable repeat to hold the tab character, but you could just replace the $repeat with the tab character in single quotes in the sequence element. Note: This variable can be of a length greater than 1, which creates a whole bunch of possibilities.
It does not use recursion, so it won't run into a recursion limit.
I don't know the maximum value you can use for count, but I tested it up to 10,000.
Globally define a long enough array of tabs:
<xsl:variable name="TABS" select="' '" />
Then use like this:
<xsl:value-of select="fn:substring($TABS, 1, fn:number($COUNT))" />
(XSLT 1.0)
<xsl:template name="tabs">
<xsl:param name="n"/>
<xsl:if test="$n > 0"> <!-- When n = 0, output nothing. -->
<xsl:call-template name="tabs"> <!-- Recursive call: call same template... -->
<xsl:with-param name="n" select="$n - 1"/> <!-- ... for writing n - 1 tabs. -->
</xsl:call-template>
<xsl:text> </xsl:text> <!-- Add one tab character. -->
</xsl:if>
</xsl:template>
Example usage:
<xsl:call-template name="tabs">
<xsl:with-param name="n" select="3"/>
</xsl:call-template>
I've discovered an LGPL-licensed library for doing this called functx, as I was sure someone had to have already done this... This is a "standard library" type XSLT library, which contains a function called repeat-string. From the docs:
The functx:repeat-string function returns a string consisting of a given number of copies of $stringToRepeat concatenated together.
Where I use it like this in my code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:functx="http://www.functx.com">
<xsl:import href="../buildlib/functx-1.0.xsl"/>
<xsl:output omit-xml-declaration="yes" />
<xsl:variable name="INDENT" select="' '" />
....
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
</xsl:template>
<xsl:template match="data-pusher-properties">
<xsl:for-each select="property">
<xsl:choose>
...
<xsl:when test="boolean(#value = '${pusher.notifications.server}')">
<xsl:value-of select="functx:repeat-string($INDENT, #indent)" />
<xsl:text>"</xsl:text>
<xsl:value-of select="#name" />
<xsl:text>": </xsl:text>
<xsl:text>"</xsl:text>
<xsl:value-of select="$pusher.notifications.email.server" />
<xsl:text>"\
</xsl:text>
</xsl:when>
...
</xsl:choose>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
So for printing a tab character n times, call it like this:
<xsl:value-of select="functx:repeat-string(' ', n)" />
I know this question is old, but I hope this can still help someone.
Documentation for the repeat-string function

XSLT: xsl:function won't work

The following works for me:
<xsl:variable name="core" select="document('CoreMain_v1.4.0.xsd')" />
<xsl:variable name="AcRec" select="document('AcademicRecord_v1.3.0.xsd')" />
<xsl:template match="xs:element">
<xsl:variable name="prefix" select="substring-before(#type, ':')" />
<xsl:variable name="name" select="substring-after(#type, ':')" />
<xsl:choose>
<xsl:when test="$prefix = 'AcRec'">
<xsl:apply-templates select="$AcRec//*[#name=$name]">
<xsl:with-param name="prefix" select="$prefix" />
</xsl:apply-templates>
</xsl:when>
<xsl:when test="$prefix = 'core'">
<xsl:apply-templates select="$core//*[#name=$name]">
<xsl:with-param name="prefix" select="$prefix" />
</xsl:apply-templates>
</xsl:when>
</xsl:choose>
</xsl:template>
But I use the same logic to handle the lookup of elements in the current or other documents based on the prefix, matching the node name in numerous places within the stylesheet. So, after changing the stylesheet version to 2.0, I tried:
<xsl:template match="xs:element">
<xsl:value-of select="my:lookup(#type)" />
</xsl:template>
<xsl:function name="my:lookup">
<xsl:param name="attribute" />
<!-- parse the attribute for the prefix & name values -->
<xsl:variable name="prefix" select="substring-before($attribute, ':')" />
<xsl:variable name="name" select="substring-after($attribute, ':')" />
<!-- Switch statement based on the prefix value -->
<xsl:choose>
<xsl:when test="$prefix = 'AcRec'">
<xsl:apply-templates select="$AcRec//*[#name=$name]">
<xsl:with-param name="prefix" select="$prefix" />
</xsl:apply-templates>
</xsl:when>
<xsl:when test="$prefix = 'core'">
<xsl:apply-templates select="$core//*[#name=$name]">
<xsl:with-param name="prefix" select="$prefix" />
</xsl:apply-templates>
</xsl:when>
</xsl:choose>
</xsl:function>
In my reading, I have only found examples of functions that return text - none call templates. I have the impression that an xsl:function should always return text/output...
After more investigation, it is entering the my:lookup function and the variables (prefix & name) are getting populated. So it does enter the xsl:choose statement, and the hits the appropriate when test. The issue appears to be with the apply-templates - value-of is displaying the child values; copy-of does as well, which I think is odd (shouldn't the output include the xml element declarations?). Why would there be a difference if code that works in a template declaration is moved to an xsl:function?
It's been a while since I did any serious XSLT, but IIRC your problem is not in the function, but in your template:
<xsl:template match="xs:element">
<xsl:value-of select="my:lookup(#type)" />
</xsl:template>
The value-of statement won't inline the result tree returned by your function. Instead, it's going to try and reduce that result tree down into some kind of string, and inline that instead. This is why you're seeing the child values and not the elements themselves.
To inline the result tree returned by your function, you'll need to use some templates to copy the result tree into place.
So, your main template will need to change to this:
<xsl:template match="xs:element">
<xsl:apply-templates select="my:lookup(#type)" />
</xsl:template>
and you'll need some templates to do the recursive call. A quick google found a good discussion of the identity template that should do what you need.
(Please forgive any syntax errors, as I said, it's been a while ...)