Jump to content

xslt - using xsl:value-of select and xsl:template match


genox

Recommended Posts

Hi All,A newbie to the forum and the world of XML/XSLTI'm trying to create a XSLT script to convert from one XML format to another (cXML is the target format) for a system integration project.I want to be able to map values in the source XML tags to the destination cXML tags as necessary but am stumbling on problems retrieving the right elementsHere comes the code...Source XML to be converted

 <?xml version="1.0" encoding="UTF-8"?> <PublishMXPO_GOSOP xmlns="http://www.ibm.com/maximo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" creationDateTime="2010-07-07T10:22:53+01:00" transLanguage="EN" baseLanguage="EN" messageID="1278494573441131060" maximoVersion="7 1 20090627-0754 V7115-149" event="0">   <MXPO_GOSOPSet>     <PO>       <BILLTO>BAKEWELL</BILLTO>       <BILLTOATTN>PMPRBOWNUSR</BILLTOATTN>     </PO>   </MXPO_GOSOPSet> </PublishMXPO_GOSOP>

XSL script

   <?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:xalan="http://xml.apache.org/xslt">       <xsl:output method="xml" version="1.0" doctype-system="http://xml.cxml.org/schemas/cXML/1.2.020/cXML.dtd" indent="yes"/>     <xsl:variable name="version">1.2.020</xsl:variable>       <xsl:template match="/PublishMXPO_GOSOP">             <xsl:apply-templates select="PublishMXPO_GOSOP"/>     </xsl:template>       <xsl:template match="*">          <xsl:variable name="messageID" select="@messageID"/>           <xsl:variable name="timestamp" select="@creationDateTime"/>          <xsl:variable name="version" select="$version"/>                    <cXML payloadID="{$messageID}" timestamp="{$timestamp}" version="{$version}" >                      <BILLADDRESS><xsl:value-of select="*"/></BILLADDRESS>                     <BILLTOPERSON><xsl:value-of select="PublishMXPO_GOSOP/MXPO_GOSOPSet/PO/BILLTOATTN"/></BILLTOPERSON>                 </cXML>               </xsl:template>     </xsl:stylesheet>  

Current output XML

    <?xml version="1.0" encoding="UTF-8"?>    <!DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.2.020/cXML.dtd">    <cXML xmlns:xalan="http://xml.apache.org/xslt" version="1.2.020" timestamp="2010-07-07T10:22:53+01:00" payloadID="1278494573441131060">    <BILLADDRESS>               BAKEWELL          PMPRBOWNUSR          </BILLADDRESS>   <BILLTOPERSON/>   </cXML>    

I want to be able to split the two (and more) element values out into their respective target tags as below. Any clues on how to do this?This is the format I want to get to:

         <?xml version="1.0" encoding="UTF-8"?>   <!DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.2.020/cXML.dtd">    <cXML xmlns:xalan="http://xml.apache.org/xslt" version="1.2.020" timestamp="2010-07-07T10:22:53+01:00" payloadID="1278494573441131060">        <BILLADDRESS>BAKEWELL</BILLADDRESS>        <BILLTOPERSON>PMPRBOWNUSR<BILLTOPERSON/>    </cXML>       

I've only managed to get anything returned from the source XML file by using xsl:value-of select="*". Using an XPATH expression like in <BILLTOATTN> does not workAlso, when I change the first template-match statement to / from /PublishMXPO_GOSOP I lose everything in the conversion except the xml version encoding header? I thought this should select all the nodes in the whole document?Any advice on this is really appreciatedCheersEugene

Link to comment
Share on other sites

There is a namespace declaration xmlns="http://www.ibm.com/maximo"on the root element of your input XML and you need to take that into account when writing the stylesheet. With XSLT/XPath 1.0 a path 'foo' selects an element with local-name 'foo' in no namespace. To select an element in a namespace you need to bind a prefix to the namespace URI and use that prefix to qualify element names e.g.

<xsl:stylesheet   xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:mx="http://www.ibm.com/maximo"  exclude-result-prefixes="mx"  version="1.0">  <xsl:template match="mx:PublishMXPO_GOSOP">	<cXML>	  <xsl:apply-templates select="mx:MXPO_GOSOPSet/mx:PO/*"/>	</cXML>  </xsl:template>  <xsl:template match="mx:BILLTO">	<BILLADDRESS><xsl:value-of select="."/></BILLADDRESS>  </xsl:template>  <!-- add further templates here --></xsl:stylesheet>

Link to comment
Share on other sites

XSLT starts processing at the root node, and goes in on every node on every level.Also, your source XML contains namespaces, so your XSLT needs to be made aware of them.Try

<?xml version="1.0" encoding="utf-8"?><xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:xalan="http://xml.apache.org/xslt" xmlns:m="http://www.ibm.com/maximo" exclude-result-prefixes="m">	<xsl:output method="xml" version="1.0" doctype-system="http://xml.cxml.org/schemas/cXML/1.2.020/cXML.dtd" indent="yes"/>	<xsl:variable name="version">1.2.020</xsl:variable>	<xsl:template match="/m:PublishMXPO_GOSOP">		<cXML payloadID="{@messageID}" timestamp="{@creationDateTime}" version="{$version}">			<xsl:apply-templates/>		</cXML>	</xsl:template>	<xsl:template match="m:BILLTO|m:BILLTOATTN"><xsl:value-of select="." /></xsl:template></xsl:stylesheet>

[edit]Yeah... Martin beated me to it :) [/edit]

Link to comment
Share on other sites

Thanks guys for the help, its really appreciated and got me off to a good start with this.Of course my problem is a little more complex that first thought... :) I need to get all my elements within the <cXML> tags and in between some others as wellThe basic structure of the target XML is

<cXML><Header><From><Credential></Credential><Identity></Identity></From><To><Credential></Credential><Identity></Identity></To></Header><Request><OrderRequest><OrderRequestHeader/><Total><Money></Money></Total><ShipTo><Address><Name></Name><PostalAddress>...</PostalAddress><Email></Email></Address></ShipTo><BillTo><Address><Name></Name><PostalAddress>...</PostalAddress><Email></Email></Address></BillTo><Contact></Contact><Comments></Comments></OrderRequestHeader><ItemOut><ItemID></ItemID><ItemDetail>...</ItemDetail></ItemOut></Request></OrderRequest></cXML>

Where ... denotes some more attributes not shown hereI need to be able to match attributes from the source XML within the structure above in the target, file - can I use xsl:template match the way that has been described? I found you cannot nest xsl:template match tags like this:

<xsl:template match="mx:ORDERDATE">    <Request deploymentMode="test">	<OrderRequest>	<ShipTo>             <xsl:element name="OrderRequestHeader">	        <xsl:attribute name="orderDate"><xsl:value-of select="."/></xsl:attribute>	     </xsl:element>       <xsl:template match="mx:ADDRESS1">	          <xsl:element name="Name">		<xsl:attribute name="xml:lang">en</xsl:attribute>		<xsl:value-of select="."/>           </xsl:element>         </ShipTo>        </OrderRequest>     </Request>      </xsl:template></xsl:template>

I've had to resort to re-listing the parent tags for each xsl:template match tag to avoid the error - such as:

<xsl:template match="mx:ORDERDATE">    <Request deploymentMode="test">	<OrderRequest>	<ShipTo>	<xsl:element name="OrderRequestHeader">	 <xsl:attribute name="orderDate"><xsl:value-of select="."/></xsl:attribute>	  <xsl:attribute name="orderType">regular</xsl:attribute>	   <xsl:attribute name="orderVersion">1</xsl:attribute>	    <xsl:attribute name="type">new</xsl:attribute>	</xsl:element>  	</ShipTo>	</OrderRequest>	</Request>		</xsl:template><xsl:template match="mx:ADDRESS1">		<Request deploymentMode="test">	<OrderRequest>	<ShipTo>	<xsl:element name="Name">		<xsl:attribute name="xml:lang">en</xsl:attribute>		<xsl:value-of select="."/>	</xsl:element> 	</ShipTo>	</OrderRequest>		</Request>	</xsl:template>

What am I doing wrong here? Is there a easier way of doing this?Thanks again

Link to comment
Share on other sites

Archived

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

×
×
  • Create New...