Jump to content

Help Regarding Simple Transformation Scenario


sbutt

Recommended Posts

Hi Folks, I'm new to xslt transofrmation so need a little help in transforming the following example.Input:

<Persons>12</Persons>

Output:

<PassengerRPHs ListOfPassengerRPH="1 2"/>

The main thing above is to put a space between digits, 123 -> 1 2 3.It would be perfect if the transformation also handles 9101112 -> 9 10 11 12In typical java programming, i know i can tokenize it using some RE and put a space in between and concatenate, but i'm not sure how to do the same in XSLT:(Any help would be much appreciated.

Link to comment
Share on other sites

You can only do that in XSLT 2.0 unfortunatly. SAXON and AltovaXML are the only two known (and stable enough) implmentations of it. They are available for JAVA and .NET (...and COM in the case of AltovaXML).Alternatively, if you have a capable XSLT 1.0 processor, you may use the EXSLT equivalent. If you use PHP, you could instead registerPHPFunctions(), and use them from within.

Link to comment
Share on other sites

Thanks your reply, but could you please give me a small code snippet or pointer on how to handle the problem in hand using either of the possibilities?

You can only do that in XSLT 2.0 unfortunatly. SAXON and AltovaXML are the only two known (and stable enough) implmentations of it. They are available for JAVA and .NET (...and COM in the case of AltovaXML).Alternatively, if you have a capable XSLT 1.0 processor, you may use the EXSLT equivalent. If you use PHP, you could instead registerPHPFunctions(), and use them from within.
Link to comment
Share on other sites

Thanks your reply, but could you please give me a small code snippet or pointer on how to handle the problem in hand using either of the possibilities?
In which language you want to run XSLT in? OS?
Link to comment
Share on other sites

In Java: javax.xml.transform.OS: Linux/Win32
With SAXON, that would be something like:
net.sf.saxon.TransformerFactoryImpl saxonTransformerFactoryImpl = new net.sf.saxon.TransformerFactoryImpl();//If you want to set some options for the processor, you can now use the following//saxonTransformerFactoryImpl.setAttribute("optionName - you should use net.sf.saxon.FeatureKeys for that", "value for the option");javax.xml.transform.stream.StreamSource source = new javax.xml.transform.stream.StreamSource(new java.io.File("path/to/the/xml/file"));javax.xml.transform.stream.StreamSource stylesheet = new javax.xml.transform.stream.StreamSource(new java.io.File("path/to/the/xslt/file"));javax.xml.transform.stream.StreamResult output = new javax.xml.transform.stream.StreamResult(new java.io.File("path/to/the/output/file"));javax.xml.transform.Templates templates = saxonTransformerFactoryImpl.newTemplates(stylesheet);javax.xml.transform.Transformer transformer = templates.newTransformer();//If you want to set some parameters for the transformations, you can now use the following//transformer.setParameter({namespaceURI-skipIfNotInANamespace}localName, "value for the parameter");transformer.transform(source, output);

Link to comment
Share on other sites

Thanks for your reply, but actually I was talking about an "XSLT script" to handle the above problem :)Transforming this

<Persons>12</Persons>

to

<PassengerRPHs ListOfPassengerRPH="1 2"/>

Any help?

With SAXON, that would be something like:
net.sf.saxon.TransformerFactoryImpl saxonTransformerFactoryImpl = new net.sf.saxon.TransformerFactoryImpl();//If you want to set some options for the processor, you can now use the following//saxonTransformerFactoryImpl.setAttribute("optionName - you should use net.sf.saxon.FeatureKeys for that", "value for the option");javax.xml.transform.stream.StreamSource source = new javax.xml.transform.stream.StreamSource(new java.io.File("path/to/the/xml/file"));javax.xml.transform.stream.StreamSource stylesheet = new javax.xml.transform.stream.StreamSource(new java.io.File("path/to/the/xslt/file"));javax.xml.transform.stream.StreamSource output = new javax.xml.transform.stream.StreamSource(new java.io.File("path/to/the/output/file"));javax.xml.transform.Templates templates = saxonTransformerFactoryImpl.newTemplates(stylesheet);javax.xml.transform.Transformer transformer = templates.newTransformer();//If you want to set some parameters for the transformations, you can now use the following//transformer.setParameter({namespaceURI-skipIfNotInANamespace}localName, "value for the parameter");transformer.transform(source, output);

Link to comment
Share on other sites

Oh...right...well... how would you do it with regex-es? tokenize()? Anyhow, XSLT 2.0 has the same features:

<PassengerRPHs>	<xsl:attribute name="ListOfPassengerRPH"><xsl:for-each select="tokenize(Persons, '.')" xml:space="preserve"><xsl:value-of select="." /><xsl:if test="position() != last()"> </xsl:if></xsl:for-each></xsl:attribute></PassengerRPHs>

Link to comment
Share on other sites

Well i got the error: Function tokenize is not found.This is what my transformator is: \xalan-j_2_7_0\xalan.bat on Altova XMLSpy.The specs from xalan 2.7.0 says the following:An input document can be either XML 1.0 or XML 1.1. Also, a stylesheet document can be either XML 1.0 or XML 1.1. A stylesheet document must conform to the XSLT 1.0 specifications.Thanks.

Oh...right...well... how would you do it with regex-es? tokenize()? Anyhow, XSLT 2.0 has the same features:
<PassengerRPHs>	<xsl:attribute name="ListOfPassengerRPH"><xsl:for-each select="tokenize(Persons, '.')" xml:space="preserve"><xsl:value-of select="." /><xsl:if test="position() != last()"> </xsl:if></xsl:for-each></xsl:attribute></PassengerRPHs>

Link to comment
Share on other sites

Xalan is an XSLT 1.0 processor. tokenize() is only available in XSLT 2.0 processors.You need to download and use SAXON within your JAVA app.As for Altova XML Spy, again you need to download SAXON, and "connect" it properly with Altova XML Spy. How do you that - I don't know. I use Stylus Studio, and Stylus Studio has SAXON by default, so I've never needed to adjust it.

Link to comment
Share on other sites

I have build the following example:

<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:str="http://exslt.org/strings">	<xsl:template match="/">		<xsl:apply-templates select="Persons"/>	</xsl:template>	<xsl:template match="Persons">		<PassengerRPHs>			<xsl:attribute name="ListOfPassengerRPH">				<xsl:for-each select="str:tokenize(Persons, '.')" xml:space="preserve">					<xsl:value-of select="."/>					<xsl:if test="position() != last()"> </xsl:if>				</xsl:for-each>			</xsl:attribute>		</PassengerRPHs>	</xsl:template></xsl:stylesheet>

with input:

<?xml version="1.0" encoding="UTF-8"?><Persons>12</Persons>

and the output was:

<?xml version="1.0" encoding="UTF-8"?><PassengerRPHs xmlns:str="http://exslt.org/strings" xmlns:fo="http://www.w3.org/1999/XSL/Format" ListOfPassengerRPH=""/>

where the "ListOfPassengerRPH" is empty?

Xalan is an XSLT 1.0 processor. tokenize() is only available in XSLT 2.0 processors.You need to download and use SAXON within your JAVA app.As for Altova XML Spy, again you need to download SAXON, and "connect" it properly with Altova XML Spy. How do you that - I don't know. I use Stylus Studio, and Stylus Studio has SAXON by default, so I've never needed to adjust it.
Link to comment
Share on other sites

This may get you started with XSLT 1.1 (uses recursion to separate the numbers). I know that you requested 91011 be shown as 9 10 11, but to do that I need a wider sample of your data to see if some rules can be derived

		<xsl:template match="Persons">			<PassengerRPHs>				<xsl:attribute name="ListOfPassengerRPH">				<xsl:variable name="PassList">					<xsl:call-template name="AddSpace">						<xsl:with-param name="value" select="text()"/>					</xsl:call-template>				</xsl:variable>					<xsl:value-of select="normalize-space($PassList)"/>				</xsl:attribute>			</PassengerRPHs>		</xsl:template>		<xsl:template name="AddSpace">			<xsl:param name="value" />			<xsl:param name="count" select="1" />			<xsl:if test="$count < string-length($value) + 1">				<xsl:value-of select="concat(substring($value,$count,1),' ')"/>				<xsl:call-template name="AddSpace">					<xsl:with-param name="value" select="$value" />					<xsl:with-param name="count" select="$count+1" />				</xsl:call-template>			</xsl:if>		</xsl:template>

Link to comment
Share on other sites

Thanks Dude - much appreciated!for 9101112..the element's data would always be a sequence stating from 1<Persons>123456789101112</Persons>

This may get you started with XSLT 1.1 (uses recursion to separate the numbers). I know that you requested 91011 be shown as 9 10 11, but to do that I need a wider sample of your data to see if some rules can be derived
		<xsl:template match="Persons">			<PassengerRPHs>				<xsl:attribute name="ListOfPassengerRPH">				<xsl:variable name="PassList">					<xsl:call-template name="AddSpace">						<xsl:with-param name="value" select="text()"/>					</xsl:call-template>				</xsl:variable>					<xsl:value-of select="normalize-space($PassList)"/>				</xsl:attribute>			</PassengerRPHs>		</xsl:template>		<xsl:template name="AddSpace">			<xsl:param name="value" />			<xsl:param name="count" select="1" />			<xsl:if test="$count < string-length($value) + 1">				<xsl:value-of select="concat(substring($value,$count,1),' ')"/>				<xsl:call-template name="AddSpace">					<xsl:with-param name="value" select="$value" />					<xsl:with-param name="count" select="$count+1" />				</xsl:call-template>			</xsl:if>		</xsl:template>

Link to comment
Share on other sites

try this one. I didn't account for 100 101 etc... Is that an issue?

		<xsl:template match="Persons">			<PassengerRPHs>				<xsl:attribute name="ListOfPassengerRPH">				<xsl:variable name="PassList">					<xsl:call-template name="AddSpace">						<xsl:with-param name="value" select="text()"/>					</xsl:call-template>				</xsl:variable>					<xsl:value-of select="normalize-space($PassList)"/>				</xsl:attribute>			</PassengerRPHs>		</xsl:template>		<xsl:template name="AddSpace">			<xsl:param name="value" />			<xsl:param name="count" select="1" />			<xsl:variable name="chars_to_separate">				<xsl:choose>					<xsl:when test="$count > 9">2</xsl:when>					<xsl:otherwise>1</xsl:otherwise>				</xsl:choose>			</xsl:variable>			<xsl:if test="$count < string-length($value) + 1">				<xsl:value-of select="concat(substring($value,$count,$chars_to_separate),' ')"/>				<xsl:call-template name="AddSpace">					<xsl:with-param name="value" select="$value" />					<xsl:with-param name="count" select="$count+$chars_to_separate" />				</xsl:call-template>			</xsl:if>		</xsl:template>

Link to comment
Share on other sites

Thanks Buddy!

try this one. I didn't account for 100 101 etc... Is that an issue?
		<xsl:template match="Persons">			<PassengerRPHs>				<xsl:attribute name="ListOfPassengerRPH">				<xsl:variable name="PassList">					<xsl:call-template name="AddSpace">						<xsl:with-param name="value" select="text()"/>					</xsl:call-template>				</xsl:variable>					<xsl:value-of select="normalize-space($PassList)"/>				</xsl:attribute>			</PassengerRPHs>		</xsl:template>		<xsl:template name="AddSpace">			<xsl:param name="value" />			<xsl:param name="count" select="1" />			<xsl:variable name="chars_to_separate">				<xsl:choose>					<xsl:when test="$count > 9">2</xsl:when>					<xsl:otherwise>1</xsl:otherwise>				</xsl:choose>			</xsl:variable>			<xsl:if test="$count < string-length($value) + 1">				<xsl:value-of select="concat(substring($value,$count,$chars_to_separate),' ')"/>				<xsl:call-template name="AddSpace">					<xsl:with-param name="value" select="$value" />					<xsl:with-param name="count" select="$count+$chars_to_separate" />				</xsl:call-template>			</xsl:if>		</xsl:template>

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...