ONYX - 9.0 - Usage
Pre-processing XML Files Using XSLT
Sommaire
- 1 Introduction
- 2 Principles
- 3 Benefits
- 4 Calls
- 5 Sample XSLT Sheets
Introduction
This page covers the basic principles of XSLT (eXtensible Stylesheet Language Transformations). Mapping will not support XSLT files developed by its users (customers or partners).
Principles
Mapping Onyx introduces support for XSLT so the user can edit the structure of an XML file.
The transformations can be called directly and natively from within Designer, or natively from the rules engine using a specific box in a Workflow.
This feature is new in Onyx and enables the user to modify an XMLDRAW data stream (see details below in Benefits).
Benefits
The main benefit of this new feature is the ability to process a generic input data stream while keeping a customized output data stream.
You can easily edit the input data stream processed by Mapping without making any changes to the program it is generated from. For any given document, you can (among others):
- Filter information
- Sort table rows
- Manage widows and orphans (line blocks that must be on the same page)
- Add information to simplify design
- Convert date formats
Calls
There are two ways to call XSLT sheets:
Workflow
To use XSL Transformation from the Mapping rules engine (Workflow), you need to use a CMD box and call the M-XSLTransform program using the command below:
[%PATH_BIN%]/M-XSLTransform "[%MAP_FILE_IN%]" "[%PATH_XSL%]/MyXSLsheet.xsl" "[%MAP_FILE_OUT%]"
Supported variables:
- PATH_BIN: path to the folder containing Mapping binaries (Applications folder under Onyx Windows or Bin under Onyx Linux)
- PATH_XSL: path to the folder containing XSL sheets
- MAP_FILE_IN: path + name of the infile specified in the workflow's box
- MAP_FILE_OUT: path + name of the outfile specified in the workflow's box
Designer
XSL Transformation sheets can also be called directly from within Designer. The advantage over using the Workflow is the native integration in Designer as the XSL sheet helps to customize the document (sorting lines, deleting lines, adding lines, managing widows and orphans, etc.) and is fully integrated into the Designer template.
To do this, copy and paste the content of the XSLT sheet into the XML Pre-processing window in Designer between the #xsltransform; and #endxsltransform; tags
Syntax:
#xsltransform;
//XSLT sheet content
#endxsltransform;
Sample XSLT Sheets
As we usually transform an XMLDRAW file into another XMLDRAW file, you can create sample XSLT templates with specific functionality:
The content below is based on a simple input data stream. Different examples highlight the differences with the "generic shell" that explain how the expected results are produced.
Generic shell - Simple copy of the input datastream
This example has no function in itself (because there is no point in applying an XSL transformation process if no change is made to the data stream) but will be used in all subsequent examples as the generic data stream.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:fn="http://www.w3.org/2005/xpath-functions" version="2.0" exclude-result-prefixes="xsl fo xs fn"> <xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="no" cdata-section-elements="field"/> <xsl:template match="@*|*|comment()"> <xsl:copy> <xsl:apply-templates select="@*|*|text()|comment()|processing-instruction()"/> </xsl:copy> </xsl:stylesheet>
Hint:
XSL sheet header
Simple copy template
Deleting lines from a group
This example deletes the lines of type info_remise and info_compo from all article groups in the document.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:fn="http://www.w3.org/2005/xpath-functions" version="2.0" exclude-result-prefixes="xsl fo xs fn"> <xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="no" cdata-section-elements="field"/> <xsl:template match="/doc/page/group[@name='Article']/line[@name='info_remise']"/> <xsl:template match="/doc/page/group[@name='Article']/line[@name='info_compo']"/> <xsl:template match="@*|*|comment()"> <xsl:copy> <xsl:apply-templates select="@*|*|text()|comment()|processing-instruction()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
Adding a first and last line to a group
In all groups
This example adds a start line (first_line) and an end line (last_line) to all groups in the input file.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:fn="http://www.w3.org/2005/xpath-functions" version="2.0" exclude-result-prefixes="xsl fo xs fn"> <xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="no" cdata-section-elements="field"/> <xsl:template match="group"> <xsl:copy> <xsl:apply-templates select="@*"/> <line name="first_line"/> <xsl:apply-templates/> <line name="last_line"/> </xsl:copy> </xsl:template> <xsl:template match="@*|*|comment()"> <xsl:copy> <xsl:apply-templates select="@*|*|text()|comment()|processing-instruction()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
In a specific group - Article
This example adds a start line (first_line) and an end line (last_line) only to the Article group(s) of the file.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:fn="http://www.w3.org/2005/xpath-functions" version="2.0" exclude-result-prefixes="xsl fo xs fn"> <xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="no" cdata-section-elements="field"/> <xsl:template match="group[@name='Article']"> <group name="Article"> <line name="first_line"/> <xsl:apply-templates/> <line name="last_line"/> </group> </xsl:template> <xsl:template match="@*|*|comment()"> <xsl:copy> <xsl:apply-templates select="@*|*|text()|comment()|processing-instruction()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
Deleting all groups: group1
This example deletes all group1 groups (found in /doc/page) from the file.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:fn="http://www.w3.org/2005/xpath-functions" version="2.0" exclude-result-prefixes="xsl fo xs fn"> <xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="no" cdata-section-elements="field"/> <xsl:template match="/doc/page/group[@name='group1']"/> <xsl:template match="@*|*|comment()"> <xsl:copy> <xsl:apply-templates select="@*|*|text()|comment()|processing-instruction()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
Sorting the lines of group1 groups in descending order
This example sorts all the lines in group1 in descending order based on the name attribute
XSLT sheet:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:fn="http://www.w3.org/2005/xpath-functions" version="2.0" exclude-result-prefixes="xsl fo xs fn"> <xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="no" cdata-section-elements="field"/> <xsl:template match="/doc/page/group[@name='group1']"> <xsl:copy> <xsl:apply-templates select="@*"/> <xsl:apply-templates> <xsl:sort select="./@name" data-type="text" order="descending"/> </xsl:apply-templates> </xsl:copy> </xsl:template> <xsl:template match="@*|*|comment()"> <xsl:copy> <xsl:apply-templates select="@*|*|text()|comment()|processing-instruction()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
Sample input XML file :
<doc> <page> <field name="field1">ValueField1</field> <field name="field2">ValueField2</field> <group name="group1"> <line name="line1"> <field name="field1">ValueField1</field> <field name="field2">ValueField2</field> </line> <line name="line2"> <field name="field1">ValueField1</field> <field name="field2">ValueField2</field> </line> <line name="line3"> <field name="field1">ValueField1</field> <field name="field2">ValueField2</field> </line> </group> <group name="group2"> <line name="line1"> <field name="field1">ValueField1</field> <field name="field2">ValueField2</field> </line> <line name="line2"> <field name="field1">ValueField1</field> <field name="field2">ValueField2</field> </line> </group> </page> </doc>
Generated output data stream:
<?xml version="1.0" encoding="utf-8"?> <doc> <page> <field name="field1">ValueField1</field> <field name="field2">ValueField2</field> <group name="group1"> <line name="line3"> <field name="field1">ValueField1</field> <field name="field2">ValueField2</field> </line> <line name="line2"> <field name="field1">ValueField1</field> <field name="field2">ValueField2</field> </line> <line name="line1"> <field name="field1">ValueField1</field> <field name="field2">ValueField2</field> </line> </group> <group name="group2"> <line name="line1"> <field name="field1">ValueField1</field> <field name="field2">ValueField2</field> </line> <line name="line2"> <field name="field1">ValueField1</field> <field name="field2">ValueField2</field> </line> </page> </doc>
Sorting, rearranging, grouping lines
This example:
- Sorts info_livraison lines in Article groups in alphabetical ascending order based on the Date_LivConf field
- Shows the other lines in the Article group in a given order: Info_livraison, then info_article, then info_remise, then info_compo and finally all lines starting with a size value
- Writes the info_livraison line only if the value of its date_LivConf field is different from the previous info_livraison line
XSLT sheet:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.0" exclude-result- prefixes="xsl xs"> <xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="no" cdata-section-elements="field"/> <xsl:template match="/doc/page"> <page> <xsl:apply-templates select="*[not(self::group[@name='Article'])]"/> <xsl:apply-templates select="group[@name='Article']"> <xsl:sort select="line[@name='info_livraison']/field[@name='Date_LivConf']" data-type="text" order="ascending"/> </xsl:apply-templates> </page> </xsl:template> <xsl:template match="group[@name='Article']"> <group name="Article"> <xsl:if test="not(preceding-sibling::group[@name='Article']/line[@name='info_livraison']/field[@name='Date_LivConf'] = ./line[@name='info_livraison']/field[@name='Date_LivConf'])"> <xsl:apply-templates select="./line[@name='info_livraison']"/> </xsl:if> <xsl:apply-templates select="./line[@name='info_article']"/> <xsl:apply-templates select="./line[@name='info_remise']"/> <xsl:apply-templates select="./line[@name='info_compo']"/> <xsl:apply-templates select="./line[starts-with(@name, 'tailles')]"> <xsl:sort select="@name" data-type="text" order="ascending"/> </xsl:apply-templates> </group> </xsl:template> <xsl:template match="@*|*|comment()"> <xsl:copy> <xsl:apply-templates select="@*|*|text()|comment()|processing-instruction()"/> </xsl:copy> </xsl:template> </xsl:stylesheet>
Sample input XML file (showing only Article groups to improve readability):
<group name="Article"> <line name="info_livraison"> <field name="Date_LivDem">2ème Qz Septembre 2014</field> <field name="Sem_LivDem">39</field> <field name="Date_LivConf">20181020</field> //this line is sorted by Date_LivConf <field name="Sem_LivConf">39</field> </line> <line name="info_article"> <field name="Reference">HOLDEN734</field> <field name="Designation"><![CDATA[HOLDEN Blanc]]></field> </line> //the 2 lines are in reverse order as the XSL template shows info_remise before info_compo <line name="info_compo"> <field name="Composition"><![CDATA[98% Polyester-2% Coton]]></field> </line> <line name="info_remise"> <field name="Remise_Totale_Ligne">5</field> </line> <line name="tailles_1"> <field name="Qte">20</field> <field name="Unt_Oeuvre">U</field> <field name="Lib_Unt_Oeuvre"><![CDATA[Unité(s)]]></field> </line> </group> <group name="Article"> //this line is not displayed as the value of Date_LivConf in the previous info_livraison line is the same (20181020) <line name="info_livraison"> <field name="Date_LivDem">2ème Qz Septembre 2014</field> <field name="Sem_LivDem">39</field> <field name="Date_LivConf">20181020</field> <field name="Sem_LivConf">39</field> </line> <line name="info_article"> <field name="Reference">HOLDEN734</field> <field name="Designation"><![CDATA[HOLDEN Blanc]]></field> </line> //the 2 lines are in reverse order as the XSL template shows info_remise before info_compo <line name="info_compo"> <field name="Composition"><![CDATA[98% Polyester-2% Coton]]></field> </line> <line name="info_remise"> <field name="Remise_Totale_Ligne">5,5</field> </line> <line name="tailles_1"> <field name="Qte">20</field> <field name="Unt_Oeuvre">U</field> <field name="Lib_Unt_Oeuvre"><![CDATA[Unité(s)]]></field> </line> </group> <group name="Article"> <line name="info_livraison"> <field name="Date_LivDem">2ème Qz Septembre 2014</field> <field name="Sem_LivDem">39</field> <field name="Date_LivConf">20190101</field> //this line is sorted by Date_LivConf <field name="Sem_LivConf">39</field> </line> <line name="info_article"> <field name="Reference">HOLDEN734</field> <field name="Designation"><![CDATA[HOLDEN Blanc]]></field> </line> <line name="info_compo"> <field name="Composition"><![CDATA[98% Polyester-2% Coton]]></field> </line> <line name="tailles_1"> <field name="Qte">20</field> <field name="Unt_Oeuvre">U</field> <field name="Lib_Unt_Oeuvre"><![CDATA[Unité(s)]]></field> </line> </group> <group name="Article"> <line name="info_livraison"> <field name="Date_LivDem">2ème Qz Septembre 2014</field> <field name="Sem_LivDem">39</field> <field name="Date_LivConf">20160101</field> //this line is sorted by Date_LivConf <field name="Sem_LivConf">39</field> </line> <line name="info_article"> <field name="Reference">HOLDEN734</field> <field name="Designation"><![CDATA[HOLDEN Blanc]]></field> </line> <line name="info_compo"> <field name="Composition"><![CDATA[98% Polyester-2% Coton]]></field> </line> <line name="tailles_1"> <field name="Qte">20</field> <field name="Unt_Oeuvre">U</field> <field name="Lib_Unt_Oeuvre"><![CDATA[Unité(s)]]></field> </line> <line name="tailles_2"> <field name="Qte">2</field> <field name="Unt_Oeuvre">U</field> <field name="Lib_Unt_Oeuvre"><![CDATA[Unité(s)]]></field> </line> </group>
XML generated (showing only Article groups for improved readability):
<group name="Article"> <line name="info_livraison"> <field name="Date_LivDem"><![CDATA[2ème Qz Septembre 2014]]></field> <field name="Sem_LivDem"><![CDATA[39]]></field> <field name="Date_LivConf"><![CDATA[20160101]]></field> <field name="Sem_LivConf"><![CDATA[39]]></field> </line> <line name="info_article"> <field name="Reference"><![CDATA[HOLDEN734]]></field> <field name="Designation"><![CDATA[HOLDEN Blanc]]></field> </line> <line name="info_compo"> <field name="Composition"><![CDATA[98% Polyester-2% Coton]]></field> </line> <line name="tailles_1"> <field name="Qte"><![CDATA[20]]></field> <field name="Unt_Oeuvre"><![CDATA[U]]></field> <field name="Lib_Unt_Oeuvre"><![CDATA[Unité(s)]]></field> </line> <line name="tailles_2"> <field name="Qte"><![CDATA[2]]></field> <field name="Unt_Oeuvre"><![CDATA[U]]></field> <field name="Lib_Unt_Oeuvre"><![CDATA[Unité(s)]]></field> </line> </group> <group name="Article"> <line name="info_livraison"> <field name="Date_LivDem"><![CDATA[2ème Qz Septembre 2014]]></field> <field name="Sem_LivDem"><![CDATA[39]]></field> <field name="Date_LivConf"><![CDATA[20181020]]></field> <field name="Sem_LivConf"><![CDATA[39]]></field> </line> <line name="info_article"> <field name="Reference"><![CDATA[HOLDEN734]]></field> <field name="Designation"><![CDATA[HOLDEN Blanc]]></field> </line> <line name="info_remise"><field name="Remise_Totale_Ligne"><![CDATA[5]]></field> </line> <line name="info_compo"> <field name="Composition"><![CDATA[98% Polyester-2% Coton]]></field> </line> <line name="tailles_1"> <field name="Qte"><![CDATA[20]]></field> <field name="Unt_Oeuvre"><![CDATA[U]]></field> <field name="Lib_Unt_Oeuvre"><![CDATA[Unité(s)]]></field> </line> </group> <group name="Article"> <line name="info_article"> <field name="Reference"><![CDATA[HOLDEN734]]></field> <field name="Designation"><![CDATA[HOLDEN Blanc]]></field> </line> <line name="info_remise"> <field name="Remise_Totale_Ligne"><![CDATA[5,5]]></field> </line> <line name="info_compo"> <field name="Composition"><![CDATA[98% Polyester-2% Coton]]></field> </line> <line name="tailles_1"> <field name="Qte"><![CDATA[20]]></field> <field name="Unt_Oeuvre"><![CDATA[U]]></field> <field name="Lib_Unt_Oeuvre"><![CDATA[Unité(s)]]></field> </line> </group> <group name="Article"> <line name="info_livraison"> <field name="Date_LivDem"><![CDATA[2ème Qz Septembre 2014]]></field> <field name="Sem_LivDem"><![CDATA[39]]></field> <field name="Date_LivConf"><![CDATA[20190101]]></field> <field name="Sem_LivConf"><![CDATA[39]]></field> </line> <line name="info_article"> <field name="Reference"><![CDATA[HOLDEN734]]></field> <field name="Designation"><![CDATA[HOLDEN Blanc]]></field> </line> <line name="info_compo"> <field name="Composition"><![CDATA[98% Polyester-2% Coton]]></field> </line> <line name="tailles_1"> <field name="Qte"><![CDATA[20]]></field> <field name="Unt_Oeuvre"><![CDATA[U]]></field> <field name="Lib_Unt_Oeuvre"><![CDATA[Unité(s)]]></field> </line> </group>