Converting to text file after XSL transformation AX 2012

Question Status

Unanswered
Alok Shrestha asked a question on 22 Aug 2013 8:51 AM

I managed to perform the XSLT transformation in an input XML file and generate the transformed output XML file. Now, the requirement I am getting is that the output file should be a text file instead of a XML file. Is there any standard functionality to generate the transformed text file instead of XML file in AX 2012?

Reply
Martin Dráb responded on 22 Aug 2013 11:02 AM

Yes, that's fully supported by XSLT. For example, try this template with your message from the previous question:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:Message="http://schemas.microsoft.com/dynamics/2011/01/documents/Message"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">   <xsl:output method="text" encoding="utf-8"/>   <xsl:template match="Message:Envelope">     <xsl:value-of select="Message:Body"/>   </xsl:template> </xsl:stylesheet>

Also, please consider closing your previous question as answered.

Reply
Alok Shrestha responded on 22 Aug 2013 11:14 AM

I tried as you have mentioned and it just works perfect in visual studio but when I try the same thing in the AX 2012, it just produces the .xml file.

Reply
Martin Dráb responded on 22 Aug 2013 12:26 PM

I tried a simple example and it works for me. Because you didn't tell us what you're doing, I have no idea what you're doing wrong.

Reply
Alok Shrestha responded on 22 Aug 2013 12:34 PM

I am trying to implement the standard positive pay functionality that comes with cumulative updates 6 in AX 2012. The requirement is that I need to generate the .txt file instead of .xml file after xslt transformation. I thought I can just generate the .txt file by change the method attribute to "text" instead of "xml" in xslt file but AX 2012 keeps on storing .xml file only, not the .txt file. Did you generate the .txt file in AX 2012 only?

Reply
Martin Dráb responded on 22 Aug 2013 12:51 PM

I'm confused. Are you talking about transformation to plain text or saving a file with .txt extension?

Reply
Alok Shrestha responded on 22 Aug 2013 12:54 PM

Sorry for the confusion. I am talking about the transformation to the plain text and the file should be saved with .txt extension. It should just be a simple .txt file with plain text in it.

Reply
Martin Dráb responded on 22 Aug 2013 1:01 PM

About transformation, you said it already worked for you in VS, you just have to find out what you have wrong in AX. I don't have enough information to reproduce the problem.

About file extension, that's not supported. You would have to modify the standard file system adapter or create a custom one (it's defined in AifFileSystemSendAdapter.getNewOutFileName()).

Reply
Andrew Martin responded on 26 Mar 2014 11:48 AM

Martin - I came across this question as I am having the same difficulty implementing positive pay in 2012.  The issue is that the output of the xslt transformation is still continuing to be wrapped in an AIF Message:

<?xml version="1.0" encoding="UTF-8"?><Envelope xmlns="schemas.microsoft.com/.../Message"><Header><MessageId>{AD130A63-D1FB-46AB-8844-00AC470066F4}</MessageId><Action>tempuri.org/.../Header><Body><MessageParts xmlns="schemas.microsoft.com/.../Message"><Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.02" xmlns:xsi="www.w3.org/.../XMLSchema-instance">

0003456700004000000000000000120110203ADDITIONAL DATA                Property Management                                         PAYEE 2                                                              

0003456700000680000000000000220110203ADDITIONAL DATA                City Power & Light                                          PAYEE 2                                                              

0003456700007800000000000000320110202ADDITIONAL DATA                City-wide Advertising                                       PAYEE 2                              

The file specification that we are working on for positive is a straight text file so the XML Message block cannot be included.

How do we get rid of that?  Do we have to apply a .Net assembly in the pipeline after the xslt transform?  The .Net assembly would be tasked with striping the XML out.  Something similar to what occurs when you import a CSV and need to convert to XML, just the reverse.  Thanks.

Andrew

Reply
Alok Shrestha responded on 26 Mar 2014 12:04 PM

Andrew,

              As I started this thread, I am writing what I did to fix this issue.  I used .NET assembly directly in the AifFileSystemSendAdapter class with some conditions to achieve similar requirement. I just used .NET XSLCompiledTransform class along with XSL transformation as below to transfer the XML file to .txt file. 

System.IO.TextWriter textwriter;

System.Xml.Xsl.XslCompiledTransform managedTransform;

xslFile=CustVendAifPaymTable.TextXSLT;
managedTransform.Load(xslFile,xslt_settings,new System.Xml.XmlUrlResolver());

textwriter= new System.IO.StreamWriter(ppFilePath,false,System.Text.Encoding::get_Default());

managedTransform.Transform(xmlReader,null,textwriter);
textwriter.Close();

Thanks,

Alok 

Reply
Andrew Martin responded on 26 Mar 2014 12:39 PM

Alok,

I agree that your solution will work, but it seems like a fairly heavy handed solution that I'm sure Microsoft did not have in mind when they decided to use the AIF platform for positive pay.  I'll go down that path if I need to, but I'd like see if Martin has a comment on this.

Thanks for posting your solution.

Andrew

Reply
Martin Dráb responded on 27 Mar 2014 1:20 AM

You can inject transformations in two different places:

  1. Pipelines (supported in previous versions too) - transform message body
  2. Transforms (new in AX2012) - transform the whole message (including headers)

See About the AIF Pipeline and Transforms for details.

You mentioned a pipeline, but it seems that you want a transform.

Reply
mouni responded on 6 Sep 2016 4:32 PM

Hi Alok,

Can you be more specific on what has to be done and steps to be followed..?

I am able to generate xml file , but would want it in plain text file. Can you be more specific in the approach you followed. What are the classes to be customized..? How is the performance coming along with this solution because we are looking to implement this in 20-25 entities in AX.  Do we have to specify entity specific ports for this setup ..? (sure I would want to have files generated in different folders for different companies-so is the solution create as many ports for as many companies we need to setup) ..

Thanks in advance for your reply

Reply
Martin Dráb responded on 6 Sep 2016 11:30 PM

Unless you have some special requirements that you forgot to mention, there are no classes to change, because it's a standard functionality. Please click the link in my previous reply and read how it works.

Reply
Alok Shrestha responded on 7 Sep 2016 10:07 AM

Hi Mouni,

             I ended up creating two XSL files to generate text file out of XML file created by AX.

First XSL file formats the AX generated XML file into something I can parse easily to create a txt file.

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="www.w3.org/.../Transform"
xmlns:Message="schemas.microsoft.com/.../Message"
xmlns:BankPositivePay="schemas.microsoft.com/.../BankPositivePay">
  <xsl:output method="xml" indent="yes" encoding="utf-8" omit-xml-declaration="no"/>
  <xsl:template match="/">
    <header>
        <xsl:for-each select="//BankPositivePay:BankPositivePay/BankPositivePay:BankAccountTable/BankPositivePay:BankChequeTable">
        <records>
              <record>
                <xsl:value-of select="BankPositivePay:AccountID"/>
              </record>
              <record1>
                <xsl:value-of select="//BankPositivePay:BankAccountTable/BankPositivePay:AccountNum"/>
              </record1>
              <record2>
                <xsl:value-of select="BankPositivePay:ChequeStatus"/>
              </record2>
              <record3>
                <xsl:value-of select="BankPositivePay:ChequeNum"/>
              </record3>
              <record4>
                <xsl:value-of select="BankPositivePay:AmountCur"/>
              </record4>
              <record5>
                <xsl:value-of select="BankPositivePay:TransDate"/>
              </record5>
              <record6>
                <xsl:value-of select="BankPositivePay:RecipientAccountNum"/>
              </record6>
              <record7>
                <xsl:value-of select="BankPositivePay:VendTable/BankPositivePay:Name"/>
              </record7>
	       <record8>
                <xsl:value-of select="//BankPositivePay:BankAccountTable/BankPositivePay:RegistrationNum"/>
              </record8>

        </records>
      </xsl:for-each>
    
    </header>
  </xsl:template>
</xsl:stylesheet>


 And then the second one parse the XML file generated in the earlier step to create a text file. As shown in the bold text below, I had to mention method attribute as "text" in XSL tag. 

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="www.w3.org/.../Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:Message="schemas.microsoft.com/.../Message"
xmlns:BankPositivePay="schemas.microsoft.com/.../BankPositivePay">
  <xsl:output method="text" indent="yes" encoding="utf-8" omit-xml-declaration="no"/>
  <msxsl:script language="JScript" implements-prefix="Message">
    <![CDATA[
    function currentDate() {
    var systemDate=new Date();
    var month=systemDate.getMonth()+1;
    var date=systemDate.getDate();
    if(month < 10){
      month="0"+month;
    } 
    if(date<10){
      date="0"+date;
    }
      return systemDate.getFullYear()+""+month+""+date;
   }
    ]]>
  </msxsl:script>
  <xsl:template match="/">
    <header>
      <records>
        <xsl:variable name="registrationnum1" select="//*/*/*/*/*[local-name()='record8']">
        </xsl:variable>
        <xsl:value-of select="format-number($registrationnum1, '000000000')"/>
        <xsl:variable name="accountNo" select="//*/*/*/*/*[local-name()='record1']">
        </xsl:variable>
        <xsl:value-of select="format-number($accountNo, '000000000000')"/>
        <xsl:text>H                        </xsl:text>
        <xsl:value-of select="Message:currentDate()"/>
        <xsl:text>&#xa;</xsl:text>
        <xsl:for-each select="//*/*/*/*[local-name()='records']">
	  <record8>
            <xsl:variable name="registrationnum2" select="*[local-name()='record8']">
            </xsl:variable>
            <xsl:value-of select="format-number($registrationnum2, '000000000')"/>
          </record8>
          <record1>
            <xsl:variable name="accountnum" select="*[local-name()='record1']">
            </xsl:variable>
            <xsl:value-of select="format-number($accountnum, '000000000000')"/>
          </record1>
          <record2>
            <xsl:variable name="checkstatus" select="*[local-name()='record2']">
            </xsl:variable>
            <xsl:choose>
              <xsl:when test="$checkstatus='Rejected'">
                <xsl:text>V</xsl:text>
              </xsl:when>
              <xsl:otherwise>
                <xsl:text>O</xsl:text>
              </xsl:otherwise>
            </xsl:choose>
          </record2>
          <record3>
            <xsl:variable name="checknum" select="*[local-name()='record3']">
            </xsl:variable>
            <xsl:value-of select="format-number($checknum,'0000000000')"/>
          </record3>
          <record4>
            <xsl:variable name="amount" select="*[local-name()='record4']">
            </xsl:variable>
            <xsl:value-of select="concat(substring(format-number($amount, '0000000000.00'),1,10),substring(format-number($amount, '0000000000.00'),12,2))"/>
          </record4>
          <record5>
            <xsl:variable name="date" select="*[local-name()='record5']">
            </xsl:variable>
            <xsl:value-of select="concat(substring($date, 1, 4), '', substring($date, 6, 2),'', substring($date, 9, 2))"/>
          </record5>
          <record6>
            <xsl:text>&#xA0;</xsl:text>
          </record6>
          <record7>
            <xsl:value-of select="*[local-name()='record7']"/>
          </record7>
          <xsl:text>&#160;</xsl:text>
          <xsl:text>&#xa;</xsl:text>
        </xsl:for-each>
      </records>
    </header>
  </xsl:template>
</xsl:stylesheet>

Let me know if that helps. 

Thanks,

Reply