Extracting a number from a string in a XSLT file - regex

Is there a way to extract a number from a string after a set of characters.
Our software uses XSLT files to convert emails into XML files. In the Subject line of an email there can be a reference to an already opened Incident/Service Request/Task.
For example - the Subject of an email could be:
RE: SR#51417: D_SATTER-NOV60LKA-I_G-A0201244
I want to extract the Service Request Number 51417 from the Subject.
The number will always be after the String "SR#". "SR#" could be written as "sr#", "Sr#" or "sR#".
I was trying to use the RegEx functions in XSLT but can't get it to work.
Do you have any suggestions on how to do this?
Thanks in advance.
Update
I am trying the solution provided by cyclexx. This is the Code that I have put in my XSLT File:
<xsl:when test="contains($subject, 'SR#')">
<xsl:element name="Field">
<xsl:attribute name="Name">
<xsl:text>a_eco_parentObjectType</xsl:text>
</xsl:attribute>
<xsl:value-of select="'ServiceReq'"></xsl:value-of>
</xsl:element>
<xsl:element name="Field">
<xsl:attribute name="Name">
<xsl:text>a_eco_parentObjectID</xsl:text>
</xsl:attribute>
<xsl:analyze-string select ="$subject" regex="\s*[Ss][Rr]#([0-9]+)\s*">
<xsl:matching-substring>
<SR>
<xsl:value-of select="regex-group(1)"></xsl:value-of>
</SR>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:element>
The variable $subject contains the Subject line of the Email file that is being processed. The output file just contains:
ServiceReq
and I have an error message: :Error in loading Hierarchical Object XSLT file(s)

Here a solution :)
<emails>
<email>
<subject>RE: SR#51417: D_SATTER-NOV60LKA-I_G-A0201244</subject>
</email>
<email>
<subject>RE: Sr#565465: D_SATTER-NOV60LKA-I_G-A0201244</subject>
</email>
</emails>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:template match="subject">
<xsl:variable name="v" select="." />
<xsl:analyze-string select="$v" regex="\s*[Ss][Rr]#([0-9]+)\s*">
<xsl:matching-substring>
<SR>
<xsl:value-of select="regex-group(1)" />
</SR>
</xsl:matching-substring>
<xsl:non-matching-substring>
<subject>
<xsl:value-of select="$v"/>
</subject>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
</xsl:stylesheet>

Related

Regex seems correct, but doesn't match with XSLT

I have this string:
"und", 3.96036662358691, 3.3195020746888, 3.2907085875176, 3.02795262671161, 3.5162776568275, 3.6582196231319, 4.25539102528011, 2.66244838424718, 2.92641494865261, 2.76262283971535,
I want to get the first decimal and the comma afterwards (3.96036662358691,).
Therefore I'm using this regex:
(^"\w+",\s)(\d+\.\d+,)
To use the regex in XSLT, I escaped the quotes, so the regex is now:
(^"\w+",\s)(\d+\.\d+,)
A snippet from the XSLT:
<xsl:analyze-string select="." regex="(^"\w+",\s)(\d+\.\d+,)">
<xsl:matching-substring>
<xsl:value-of select="regex-group(2)"/>
</xsl:matching-substring>
</xsl:analyze-string>
I'm using Oxygen, XSLT 3.0 and Saxon-PE 11.4.
Why is my regex only matching when looking for the pattern in the file, but not when using it with XSLT?
Some more information:
This is a snippet from the XML file (with word frequencies):
<?xml version="1.0" encoding="utf-8"?><xml>"name1", "name2", "name3", "name4", "name5", "name6", "name7", "name8", "name9", "name10",
"und", 3.96036662358691, 3.3195020746888, 3.2907085875176, 3.02795262671161, 3.5162776568275, 3.6582196231319, 4.25539102528011, 2.66244838424718, 2.92641494865261, 2.76262283971535,
"sie", 1.74547291174592, 2.69105265278169, 1.79199906147349, 4.57921899704663, 2.02015087843653, 0.786224821312541, 2.4266651652497, 5.35571214331204, 1.5944714693846, 2.0382921043714,
"die", 1.87916870924135, 2.7111952624582, 2.32578601595495, 2.36866441931923, 2.16444736975343, 2.00129954515919, 2.77011429536625, 2.09749984592313, 2.3009806192572, 2.05947136563877,</xml>
This is a snippet from my XSLT so far:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:template match="*:xml/text()">
<!-- copy all words to the very top -->
<xsl:analyze-string select="." regex="("(\w+)",)">
<xsl:matching-substring>
<xsl:value-of select="."/>
</xsl:matching-substring>
</xsl:analyze-string>
<!-- copy all word frequencies for name1 -->
<xsl:analyze-string select="." regex="(^"\w+",\s)(\d+\.\d+,)">
<xsl:matching-substring>
<xsl:text>"name1",</xsl:text>
<xsl:value-of select="regex-group(2)"/>
</xsl:matching-substring>
</xsl:analyze-string>
<!-- after that: copy all frequencies for name2 etc. -->
</xsl:template>
</xsl:stylesheet>
All in all, I'm trying to reformat a txt file to get the correct format for csv.
You haven't quite explained what you are after but I would think that adding the flags="m" attribute in
<xsl:analyze-string select="." regex="(^"\w+",\s)(\d+\.\d+,)" flags="m">
<xsl:matching-substring>
<xsl:text>"name1",</xsl:text>
<xsl:value-of select="regex-group(2)"/>
</xsl:matching-substring>
</xsl:analyze-string>
is what helps with your complete, multi-line input as that way ^ matches the beginning of each line and not simply of the input string.

Getting internal error while evaluating template - xslt

I have an issue while converting xml into csv. I'm getting a strange issue and need help.
This is my XML and XSLT, I'm getting the below error while transforming
"java.lang.RuntimeException: Internal error evaluating template at line 47 in module " that's at the line with content " xsl:template match="UsrOrder"" - bolded text
Tried but unable to figure out the issue.
XML
Below is the XML input I'm giving to XSLT and this has to be converted to CSV
<?xml version="1.0" encoding="UTF-8"?>
<document>
<businessobjects>
<UsrOrder>
<PlanOn>228.01</PlanOn>
<PROG/>
<FUND/>
<ORGN/>
<ACCT/>
<Buyer/>
<Delivery_Notes/>
<Supplier/>
<Line>1</Line>
<Item_Name>NewAir AC-12000CF Airco filter</Item_Name>
<Unit_of_Measure>STK</Unit_of_Measure>
<Order_Date/>
<Retrofit/>
<Description/>
<Product_Code/>
<Related_Invoice_Number/>
<Order_Attachments/>
<Quantity>1.0000</Quantity>
<Unit_Price>9.98</Unit_Price>
</UsrOrder>
</businessobjects>
</document>
```
XSLT
====
<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:csv="csv:csv">
<xsl:output method="text" encoding="utf-8" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<xsl:variable name="delimiter" select="','" />
<csv:columns>
<column>Supplier</column>
<column>FUND</column>
<column>ORGN</column>
<column>ACCT</column>
<column>PROG</column>
<column>PlanOn</column>
<column>Delivery_Notes</column>
<column>Buyer</column>
<column>Line</column>
<column>ItemName</column>
<column>Quantity</column>
<column>Unit_Price</column>
<column>Unit_of_Measure</column>
<column>Description</column>
<column>Product_Code</column>
<column>Category</column>
<column>Retrofit</column>
<column>Related_Invoice_Number</column>
<column>OrderDate</column>
<column>OrderAttachments</column>
</csv:columns>
<xsl:template match="/document/businessobjects">
<!-- Output the CSV header -->
<xsl:for-each select="document('')/*/csv:columns/*">
<xsl:value-of select="."/>
<xsl:if test="position() != last()">
<xsl:value-of select="$delimiter"/>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
<!-- Output rows for each matched property -->
<xsl:apply-templates select="UsrOrder" />
</xsl:template>
**<xsl:template match="UsrOrder">**
<xsl:variable name="OrderOrderLines" select="." />
<!-- Loop through the columns in order -->
<xsl:for-each select="document('')/*/csv:columns/*">
<!-- Extract the column name and value -->
<xsl:variable name="column" select="." />
<xsl:variable name="value" select="$OrderOrderLines/*[name() = $column]" />
<xsl:value-of select="$value"/>
<!-- Quote the value if required -->
<!-- <xsl:choose>
<xsl:when test="contains($value, '"')">
<xsl:variable name="x" select="replace($value, '"', '""')"/>
<xsl:value-of select="concat('"', $x, '"')"/>
</xsl:when>
<xsl:when test="contains($value, $delimiter)">
<xsl:value-of select="concat('"', $value, '"')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$value"/>
</xsl:otherwise>
</xsl:choose>-->
<!-- Add the delimiter unless we are the last expression -->
<xsl:if test="position() != last()">
<xsl:value-of select="$delimiter"/>
</xsl:if>
</xsl:for-each>
<!-- Add a newline at the end of the record -->
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
"Internal error" means it's a problem in the XSLT processor, not in your code. You can consider things like checking known bugs and upgrading to the latest maintenance release; when you've done that, report it to the vendor.
Another technique is to try a different XSLT processor and see if it comes up with anything. When I run this on the current Saxon version (9.9.1.5), I get:
Static error at xsl:template on line 31 column 53 of test.xsl:
XTSE0120: No character data is allowed between top-level elements
Errors were reported during stylesheet compilation
So it could be that if you fix the problem in your stylesheet, the failure will go away. (The characters in question are not actually on line 31, they are the asterisks on line 46.)

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

Which is the correct approach out of the two?

I'm having an XML and likes to retrieve and concatenate values
Below is the Sample XML from which we need to retrieve the values:
<?xml version="1.0" encoding="UTF-8"?>
<Document>
<docBody>
<employee>
<employeeNumber>595</employeeNumber>
</employee>
<employeeAddress>
<empAddress>1</empAddress>
<empAddress2>1</empAddress2>
</employeeAddress>
</docBody>
<Messages />
</Document>
Method1:
<xsl:template match="employee">
<xsl:variable name="empNbr">
<xsl:value-of select="employeeNumber"/>
</xsl:variable>
<xsl:variable name="empAddress">
<xsl:value-of select="../employeeDetails/employeeAddress"/>
</xsl:variable>
<xsl:variable name="empAddress2">
<xsl:value-of select="../employeeDetails/empAddress2"/>
</xsl:variable>
<xsl:value-of select="concat($empNbr,$empAddress,$empAddress2)"/>
</xsl:template>
Method2:
<xsl:template match="employee">
<xsl:value-of select="concat(<xsl:value-of select="employeeNumber"/>,
<xsl:value-of select="../employeeDetails/employeeAddress"/>,
<xsl:value-of select="../employeeDetails/empAddress2"/>)"/>
</xsl:template>
Thanks in advance.
It's usually better to write variable declarations like so
<xsl:variable name="empNbr" select="employeeNumber" />
This means empNbr now references the employeeNumber directly. By using xsl:value-of this effectively gets the text value of empNbr and assigns it to the variable.
Your second method is not valid XSLT. The expression you are looking for is this...
<xsl:value-of select="concat(employeeNumber, ../employeeDetails/employeeAddress, ../employeeDetails/empAddress2)" />
Or you could have three separate xsl:value-of statements.
<xsl:value-of select="employeeNumber"/>
<xsl:value-of select="../employeeDetails/employeeAddress"/>
<xsl:value-of select="../employeeDetails/empAddress2"/>

Duplicate fn:analyze-string() output using xsl:analyze-string?

Is it possible to generate output identical to the fn:analyze-string (XPath 3.0) using xsl:analyze-string (XSLT 2.0)?
Some examples for input string abcdefg:
regex="^a((b(c))d)(efg)$"
<s:analyze-string-result xmlns:s="http://www.w3.org/2009/xpath-functions/analyze-string">
<s:match>a<s:group nr="1">
<s:group nr="2">b<s:group nr="3">c</s:group>
</s:group>d</s:group>
<s:group nr="4">efg</s:group>
</s:match>
</s:analyze-string-result>
regex="^((a(bc)d)(.*))$
<s:analyze-string-result xmlns:s="http://www.w3.org/2009/xpath-functions/analyze-string">
<s:match>
<s:group nr="1">
<s:group nr="2">a<s:group nr="3">bc</s:group>d</s:group>
<s:group nr="4">efg</s:group>
</s:group>
</s:match>
</s:analyze-string-result>
regex="^(((a)(b)(cde)(.*)))$"
<s:analyze-string-result xmlns:s="http://www.w3.org/2009/xpath-functions/analyze-string">
<s:match>
<s:group nr="1">
<s:group nr="2">
<s:group nr="3">a</s:group>
<s:group nr="4">b</s:group>
<s:group nr="5">cde</s:group>
<s:group nr="6">fg</s:group>
</s:group>
</s:group>
</s:match>
</s:analyze-string-result>
I suspect it's not possible because xsl:analyze-string does not provide methods to: 1) know how many groups there, or 2) discover parent/child relationships of groups to facilitate recursion. But I'm curious if there is something I have overlooked.
You can make it a bit easier by changing the syntax of the regex, using <g> </g> for grouping rather than () (it would be possible but tiresome not to do this and instead analyse the regex and determine the groups)
Once you have the group structure you can generate the normal regex using () to pass to xsl:analyze-function adding extra groups so that every text run is grouped and can be retrieved later with regex-group().
Not extensively tested so there may be bugs but something like this, and it seems to work on your examples.
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:f="data:,f"
exclude-result-prefixes="xs"
>
<xsl:output omit-xml-declaration="yes"/>
<xsl:function name="f:analyze-string">
<xsl:param name="s"/>
<xsl:param name="r"/>
<xsl:variable name="rr">
<xsl:apply-templates mode="a-s" select="$r"/>
</xsl:variable>
<xsl:text>
</xsl:text>
<f:analyze-string-result>
<xsl:text>
</xsl:text>
<xsl:analyze-string select="$s" regex="{$rr}">
<xsl:matching-substring>
<f:match>
<xsl:variable name="m" select="."/>
<xsl:apply-templates mode="g" select="$r"/>
</f:match>
<xsl:text>
</xsl:text>
</xsl:matching-substring>
<xsl:non-matching-substring>
<f:non-match>
<xsl:value-of select="."/>
</f:non-match>
</xsl:non-matching-substring>
</xsl:analyze-string>
<xsl:text>
</xsl:text>
</f:analyze-string-result>
<xsl:text>
</xsl:text>
</xsl:function>
<xsl:template mode="a-s" match="g">
<xsl:text>(</xsl:text>
<xsl:apply-templates mode="a-s"/>
<xsl:text>)</xsl:text>
</xsl:template>
<xsl:template mode="a-s" match="text()[../g]">
<xsl:text>(</xsl:text>
<xsl:value-of select="."/>
<xsl:text>)</xsl:text>
</xsl:template>
<xsl:template mode="g" match="g">
<f:group>
<xsl:attribute name="nr">
<xsl:number level="any"/>
</xsl:attribute>
<xsl:apply-templates mode="g"/>
</f:group>
</xsl:template>
<xsl:template mode="g" match="text()">
<xsl:variable name="n">
<xsl:number count="g|text()[../g]" level="any"/>
</xsl:variable>
<xsl:value-of select="regex-group(xs:integer($n))"/>
</xsl:template>
<xsl:template name="main">
<!-- regex="^a((b(c))d)(efg)$" -->
<xsl:variable name="r">a<g><g>b<g>c</g></g>d</g><g>efg</g>$</xsl:variable>
<xsl:sequence select="f:analyze-string('abcdefg',$r)"/>
<!-- regex="^((a(bc)d)(.*))$ -->
<xsl:variable name="r"><g><g>a<g>bc</g>d</g><g>.*</g></g>$</xsl:variable>
<xsl:sequence select="f:analyze-string('abcdefg',$r)"/>
<!-- regex="^(((a)(b)(cde)(.*)))$" -->
<xsl:variable name="r"><g><g><g>a</g><g>b</g><g>cde</g><g>.*</g></g></g>$</xsl:variable>
<xsl:sequence select="f:analyze-string('abcdefg',$r)"/>
</xsl:template>
</xsl:stylesheet>
Produces
$ saxon9 -it main analyse.xsl
<f:analyze-string-result xmlns:f="data:,f">
<f:match>a<f:group nr="1"><f:group nr="2">b<f:group nr="3">c</f:group></f:group>d</f:group><f:group nr="4">efg</f:group></f:match>
</f:analyze-string-result>
<f:analyze-string-result xmlns:f="data:,f">
<f:match><f:group nr="1"><f:group nr="2">a<f:group nr="3">bc</f:group>d</f:group><f:group nr="4">efg</f:group></f:group></f:match>
</f:analyze-string-result>
<f:analyze-string-result xmlns:f="data:,f">
<f:match><f:group nr="1"><f:group nr="2"><f:group nr="3">a</f:group><f:group nr="4">b</f:group><f:group nr="5">cde</f:group><f:group nr="6">fg</f:group></f:group></f:group></f:match>
</f:analyze-string-result>