Reputation: 5981
I have an xml file with the below structure:
<?xml version="1.0" encoding="UTF-8" ?>
<VocaDocument xmlns:cmn="http://www.voca.com/schemas/common" xmlns:me="http://www.voca.com/schemas/messaging">
<Data>
<Document>
<StreamStart>
<Stream>
<BankName>LLOYDS BANK PLC</BankName>
<BankCode>0004</BankCode>
<StreamCode>01</StreamCode>
<VoucherSortCode>SC987654</VoucherSortCode>
<VoucherAccountNumber>99775533</VoucherAccountNumber>
</Stream>
</StreamStart>
<DDIVouchers>
<Voucher>
<TransactionCode>NEW</TransactionCode>
<OriginatorIdentification>
<ServiceUserName>A CUSTOMER</ServiceUserName>
<ServiceUserNumber>123456</ServiceUserNumber>
</OriginatorIdentification>
<PayingBankAccount>
<BankName>A BANK LTD</BankName>
<AccountName>A PERSON</AccountName>
<AccountNumber>99887766</AccountNumber>
<UkSortCode>SC123456</UkSortCode>
</PayingBankAccount>
<ReferenceNumber>BACS1234567</ReferenceNumber>
<ContactDetails>
<PhoneNumber>020 83395862</PhoneNumber>
<FaxNumber />
<Address>
<cmn:AddresseeName>A NAME</cmn:AddresseeName>
<cmn:PostalName>A CUSTOMER</cmn:PostalName>
<cmn:AddressLine>Line 1</cmn:AddressLine>
<cmn:TownName>Town</cmn:TownName>
<cmn:CountyIdentification />
<cmn:CountryName>UNITED KINGDOM</cmn:CountryName>
<cmn:ZipCode>AA1 4AB</cmn:ZipCode>
</Address>
</ContactDetails>
<ProcessingDate>2014-08-19</ProcessingDate>
<BankAccount>
<FirstLastVoucherCode>FirstLast</FirstLastVoucherCode>
<AgencyBankCode>0123</AgencyBankCode>
<SortCode>SC654321</SortCode>
<AccountNumber>12345678</AccountNumber>
<TotalVouchers>1</TotalVouchers>
<Counter />
</BankAccount>
</Voucher>
what I need to do is output the data in fixed length text format, one line for each of the Voucher elements with the Stream elements at the start of each line.
so it should look something like the below in the output file (that will be loaded up into the AS400 accounting system):
LLOYDS BANK PLC 00040001SC9876549977553300000000NEW A CUSTOMER 123456A BANK A PERSON ...
So, my question is: how could I match each Voucher record and put the Stream record at the start of each record - do I need to use a variable to store the values in the Stream element?
Once I have done that I can look into using concat with substring to maybe pad leading spaces into the output as I have see in SO 16816251: xml-to-fixed-width-text-file-with-xsl-style-sheet
Thanks for any suggestions or tips
Upvotes: 0
Views: 131
Reputation: 116982
First thing, let us take a minimal, but complete example of XML input:
<VocaDocument>
<Data>
<Document>
<StreamStart>
<Stream>
<BankName>LLOYDS BANK PLC</BankName>
</Stream>
</StreamStart>
<DDIVouchers>
<Voucher>
<TransactionCode>NEW</TransactionCode>
<OriginatorIdentification>
<ServiceUserNumber>123456</ServiceUserNumber>
</OriginatorIdentification>
</Voucher>
<Voucher>
<TransactionCode>OLD</TransactionCode>
<OriginatorIdentification>
<ServiceUserNumber>789012</ServiceUserNumber>
</OriginatorIdentification>
</Voucher>
</DDIVouchers>
</Document>
</Data>
</VocaDocument>
Next, consider the following stylesheet:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8" />
<xsl:template match="/">
<xsl:for-each select="VocaDocument/Data/Document/DDIVouchers/Voucher">
<xsl:value-of select="../../StreamStart/Stream/BankName" />
<xsl:value-of select="TransactionCode" />
<xsl:value-of select="OriginatorIdentification/ServiceUserNumber" />
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
The result here will be:
LLOYDS BANK PLCNEW123456
LLOYDS BANK PLCOLD789012
The instruction:
<xsl:for-each select="VocaDocument/Data/Document/DDIVouchers/Voucher">
puts us in the context of Voucher
. In this context, the path:
"../../StreamStart/Stream/BankName"
goes "up" to the parent element twice (i.e. to Document
) and from there "down" to StreamStart/Stream/BankName
where the required value is.
Alternatively, you could do:
<xsl:template match="/">
<xsl:variable name="BankName" select="VocaDocument/Data/Document/StreamStart/Stream/BankName" />
<xsl:for-each select="VocaDocument/Data/Document/DDIVouchers/Voucher">
<xsl:value-of select="$BankName" />
<xsl:value-of select="TransactionCode" />
<xsl:value-of select="OriginatorIdentification/ServiceUserNumber" />
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>
The problem of padding the individual values is left as an exercise for the reader (who has already found the solution).
Upvotes: 2