Ignore periods in XSLT - xslt

I want to ignore periods in XSLT
Input :
<target>
<xor type="frt">88.1234/FFT.mr.874325</xor>
<target>
Desired output :
<getone name="FRT" val="88.1234/FFTmr874325" />
Tried code :
<xsl:template name="target">
<getone name="FRT">
<xsl:attribute name="value">
<xsl:value-of select="descendant::xor[#type='frt']"/>
</xsl:attribute>
</getone>
</xsl:template>
When I am using the above code I am getting the output as
<getone name="FRT" val="88.1234/FFT.mr.874325" />
But I want to ignore the periods after /.
I am Using XSLT 2.0 version

Here's one way:
<xsl:template match="target">
<getone name="FRT">
<xsl:attribute name="value">
<xsl:value-of select="substring-before(xor[#type='frt'], '/')"/>
<xsl:text>/</xsl:text>
<xsl:value-of select="translate(substring-after(xor[#type='frt'], '/'), '.', '')"/>
</xsl:attribute>
</getone>
</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

How to concatenate xsl:value-of with separator

Given XML:
<issueDate day="30" month="09" year="2015"/>
I wanted to build a string that output: 2015-09-30
This worked:
<xsl:variable name="issueDate" as="xs:string">
<xsl:value-of select="concat(//issueDate/#year,'-',//issueDate/#month,'-',//issueDate/#day)" />
</xsl:variable>
...
<xsl:value-of select="$issueDate"/>
But this threw an error (expected EOF, found ','):
<xsl:value-of select="//issueDate/#year,//issueDate/#month,//issueDate/#day" separator="-" />
What is the syntax to select more than one value using separator attribute?
If you can use XPath-2.0/XSLT-2.0, you could use string-join:
<xsl:for-each select="//issueDate">
<xsl:value-of select="string-join( (#year, #month, #day), '-')" />
<xsl:text>
</xsl:text> <!-- just for pretty output -->
</xsl:for-each>

XSLT - get sorted information extract from cdata

I’m new in the xslt topic and have a problem that can't solve on my own.
Here e excample of my xml file:
<node>
<failure><![CDATA[
some useless information.
CRS urn:ogc:def:crs:EPSG::25830 not defined.
CRS urn:ogc:def:crs:EPSG::25833 not possible.
CRS urn:ogc:def:crs:EPSG::25830 not defined.
some useless information.]]>
</failure>
</node>
The main problem is that the information stand in a CDATA block and many different informations are mixed up. I have found a way to get them out, but only as a string value not able to differentiate between the sort.
I need a way to extract elements that fit the pattern: "CRS [-unknown-] [id] not [result]"
What i want is something like this:
<failure>
<CRS>
<id> urn:ogc:def:crs:EPSG::25830 </id>
<result> not defined </result>
</CRS>
<CRS>
<id> urn:ogc:def:crs:EPSG::25833 </id>
<result> not posible </result>
</CRS>
<CRS>
<id> urn:ogc:def:crs:EPSG::25830 </id>
<result> not defined </result>
</CRS>
</failure>
Can somebody help me or made experience with simular problems?
XSLT 2.0 has xsl:analyze-string which is designed for precisely this task, so if at all possible I suggest you upgrade to a 2.0 processor such as Saxon:
<xsl:template match="node">
<failure>
<xsl:analyze-string select="failure"
regex="^\s*CRS\s*(\S+)\s*(not\s*.*)$" flags="m">
<xsl:matching-substring>
<CRS>
<id><xsl:value-of select="regex-group(1)" /></id>
<result><xsl:value-of select="normalize-space(regex-group(2))" /></result>
</CRS>
</xsl:matching-substring>
</xsl:analyze-string>
</failure>
</xsl:template>
String manipulation facilities in XSLT 1.0 are extremely limited in comparison, and since XSLT is a functional language without updateable variables you'd have to write some sort of hideously complex set of recursive call-template logic to split up the text into separate lines and then extract the relevant bits out of each line in turn using substring-before and substring-after.
<xsl:template name="each-line">
<xsl:param name="val" />
<!-- pull out everything before the first newline and normalize (trim leading
and trailing whitespace and squash internal whitespace to a single space
character -->
<xsl:variable name="firstLine"
select="normalize-space(substring-before($val, '
'))" />
<!-- pull out everything after the first newline -->
<xsl:variable name="rest" select="substring-after($val, '
')" />
<xsl:if test="$firstLine">
<xsl:call-template name="process-line">
<xsl:with-param name="line" select="$firstLine" />
</xsl:call-template>
</xsl:if>
<!-- if there are still some non-empty lines left then process them recursively -->
<xsl:if test="normalize-space($rest)">
<xsl:call-template name="each-line">
<xsl:with-param name="val" select="$rest" />
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="process-line">
<xsl:param name="line" />
<xsl:if test="starts-with($line, 'CRS ') and contains($line, ' not ')">
<!-- here $line will be something like
"CRS urn:ogc:def:crs:EPSG::25830 not defined." -->
<CRS>
<!-- ID is everything between the first and second spaces -->
<id><xsl:value-of select="substring-before(substring-after($line, ' '), ' ')" /></id>
<!-- result is everything after the second space -->
<result><xsl:value-of select="substring-after(substring-after($line, ' '), ' ')" /></result>
</CRS>
</xsl:if>
</xsl:template>
You would call this logic using a construct like
<xsl:template match="node">
<failure>
<xsl:call-template name="each-line">
<xsl:with-param name="val" select="failure" />
</xsl:call-template>
</failure>
</xsl:template>

XSL fetch min/max of modified attributes into variables

I would like to find a "nicer" solution to get the minimum and maximum values of attributes and save them into accesible variables. I would love to get away from the for-each-loop too. How is that possible?
My XML:
<Rows>
<Entry value1="16,423" value2="18,123" />
<Entry value1="423" value2="11,588" />
<Entry value1="1,168" value2="521" />
</Rows>
And my XSL:
<xsl:for-each select="Rows/Entry/#value1|Rows/Entry/#value2">
<xsl:sort select="." data-type="number" />
<xsl:choose>
<xsl:when test="position() = 1">
<xsl:variable name="min" select="format-number(translate(.,',',''),'#')" />
</xsl:when>
<xsl:when test="position() = last()">
<xsl:variable name="max" select="format-number(translate(.,',',''),'#')" />
</xsl:when>
</xsl:choose>
</xsl:for-each>
The desired output should be $min=423 and $max=18123 as numbers and accesible outside the for-each-loop
Well there is XSLT 2.0 since 2007 (implemented by XSLT processors like Saxon 9, AltovaXML, XmlPrime) where you can simply do (assuming you have the declaration xmlns:xs="http://www.w3.org/2001/XMLSchema" on your xsl:stylesheet element):
<xsl:variable name="min" select="min(Rows/Entry/(#value1, #value2)/xs:decimal(translate(., ',', ''))"/>
<xsl:variable name="max" select="max(Rows/Entry/(#value1, #value2)/xs:decimal(translate(., ',', ''))"/>
If you really want to store a formatted string in a variable you can of course do that as well with e.g.
<xsl:variable name="min" select="format-number(min(Rows/Entry/(#value1, #value2)/xs:decimal(translate(., ',', '')), '#')"/>
<xsl:variable name="max" select="format-number(max(Rows/Entry/(#value1, #value2)/xs:decimal(translate(., ',', '')), '#')"/>
As for XSLT 1.0, there I think the sorting with for-each is the right approach but you would need to pull the xsl:variable outside the for-each e.g.
<xsl:variable name="min">
<xsl:for-each select="Rows/Entry/#value1|Rows/Entry/#value2">
<xsl:sort select="translate(., ',', '')" data-type="number"/>
<xsl:if test="position() = 1">
<xsl:value-of select="format-number(., '#')"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="max">
<xsl:for-each select="Rows/Entry/#value1|Rows/Entry/#value2">
<xsl:sort select="translate(., ',', '')" data-type="number"/>
<xsl:if test="position() = last()">
<xsl:value-of select="format-number(.,'#')" />
</xsl:if>
</xsl:for-each>
</xsl:variable>
As an alternative you could replace the for-each with apply-templates and then write a template matching #value1 | #value2 but while I think most tasks to transform nodes are better done using push style in XSLT I think for finding a minimum or maximum value the for-each is fine.
I'm not sure if it is absolutely correct but I tried this for min
(/Rows/Entry/#value1|/Rows/Entry/#value2)[not((/Rows/Entry/#value1|/Rows/Entry/#value2) < .)]
and this for max
(/Rows/Entry/#value1|/Rows/Entry/#value2)[not((/Rows/Entry/#value1|/Rows/Entry/#value2) > .)]
and it gave me values you mentioned. But for simplification I worked with xml with values without ",".

Checking the starting character should be 'T' and next 3 character should be number in xslt

I am using XSLT1.0 for transforming my XML.
I am having below Tabs.xml
<?xml version="1.0"?>
<tcm:ListItems xmlns:tcm="http://www.tridion.com/ContentManager/5.0" ID="tcm:481-87289-4" Managed="68">
<tcm:Item ID="tcm:481-596728-64" Title="T000. Brisbane" pageURL="/australia/brisbane/index.aspx" componentTitle="Overview"/>
<tcm:Item ID="tcm:481-598671-64" Title="Tabs XML"/>
<tcm:Item ID="tcm:481-598672-64" Title="T030 Special Offers" pageURL="/australia/brisbane/specialoffers.aspx" componentTitle="Special Offers"/>
<tcm:Item ID="tcm:481-598673-64" Title="020 Flight Schedules" pageURL="/australia/brisbane/flightschedules.aspx" componentTitle="Flight Schedules"/>
<tcm:Item ID="tcm:481-598674-64" Title="T010 Guide" pageURL="/australia/brisbane/guide.aspx" componentTitle="Guide"/>
</tcm:ListItems>
And I am using below xslt to transform it!
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tcm="http://www.tridion.com/ContentManager/5.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:em="http://www.emirates.com/tridion/schemas" xmlns:tcmse="http://www.tridion.com/ContentManager/5.1/TcmScriptAssistant" exclude-result-prefixes="em xlink tcmse tcm">
<xsl:output method="xml" version="1.0" encoding="UTF-16" indent="yes"/>
<xsl:template match="tcm:ListItems">
<list type="Tabs">
<xsl:apply-templates select="tcm:Item">
<xsl:sort select="#Title" order="ascending"/>
</xsl:apply-templates>
</list>
</xsl:template>
<!-- add field values for each item-->
<xsl:template match="tcm:Item">
<xsl:if test="#componentTitle != ''">
<xsl:element name="tab">
<xsl:attribute name="id">
<xsl:value-of select="substring-after(#ID, '-')"/>
</xsl:attribute>
<xsl:attribute name="title">
<xsl:value-of select="#componentTitle"/>
</xsl:attribute>
<xsl:attribute name="url">
<xsl:value-of select="#pageURL"/>
</xsl:attribute>
</xsl:element>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Previously, it was working fine, but now there is another change required, now I need those node to be rendered whose #Title starts with 'T' or 't' as well as next 3 character should be number for example in above xml "Flight Schedule" shouldn't come, I assume i just need to write one more and condition in <xsl:if test="#componentTitle != ''">,
Please suggest! how it can be done!
Here is the simplest expression that will do the matching:
translate(substring(#Title, 1, 4), 't12345679', 'T000000000') = 'T000'
Here is the template:
<xsl:template match="
tcm:Item[translate(substring(#Title, 1, 4), 't12345679', 'T000000000') = 'T000'
and #componentTitle != '' "/>
The selection logic is best put into the match pattern of the template -- and it can be a little simplified, too.
<xsl:template match=
"tcm:Item[contains('tT', substring(#Title,1,1))
and
number(substring(#Title,2,3))
=
number(substring(#Title,2,3))
]
">
One rule to remember: Always test if some string $s represents a number -- like this:
number($s) = number($s)
You should select the nodes you want to operate on in your templates in the apply-templates element:
<xsl:apply-templates select="tcm:Item[#componentTitle != ''
and (starts-with(translate(#Title, 't', 'T'), 'T')
and string(number(substring(#Title,2,3))) != 'NaN')]">
I have used the test that #solution produced for this - it works well for the requirement (tested here).
This is better than selecting all tcm:Item nodes and testing them one at a time in the template.
Working with XSLT only very occasionally, I came up with the following solution:
<xsl:if test="#componentTitle != ''">
<xsl:if test="starts-with(#Title,'T') or starts-with(#Title,'t')">
<xsl:if test="string-length(#Title) > 3">
<xsl:if test="string(number(substring(#Title,2,3))) != 'NaN'">
...
</xsl:if>
</xsl:if>
</xsl:if>
</xsl:if>
I noticed that there are also functions lower-case/upper-case which could be used for testing for the first character being a t or T but they seem to be only available in XSLT2.0 .
I came up with below solution, please suggest if it is OK!
<xsl:template match="tcm:Item">
<xsl:if test="#componentTitle != '' and (starts-with(translate(#Title, 't', 'T'), 'T')and string(number(substring(#Title,2,3))) != 'NaN')">
<xsl:element name="tab">
<xsl:attribute name="id">
<xsl:value-of select="substring-after(#ID, '-')"/>
</xsl:attribute>
<xsl:attribute name="title">
<xsl:value-of select="#componentTitle"/>
</xsl:attribute>
<xsl:attribute name="url">
<xsl:value-of select="#pageURL"/>
</xsl:attribute>
</xsl:element>
</xsl:if>
</xsl:template>
Your all input is required!