locked
Flat File Disassembler : Multiple Headers with multiple details records RRS feed

  • Question

  • Hi All...

    My input text file is as follows:

    SS,1100,07/21/2015,7/31/2015,USD,AA23-06/06/2015
    40,122015,105655.19,AA032015,20100,3001,7005339800
    50,122015,105655.19,AA032015,20100,3001,7005339800
    BB,1200,07/21/2015,7/31/2015,USD,AA03-06/06/2015
    40,132015,105655.19,AA032015,20100,3001,7005339800
    50,132015,105655.19,AA032015,20100,3001,7005339800

    In a row,if we have 6 elements then it will be  treated as Header  Record and if we have 7 elements then it will be treated as Details Record.

    output xml  of input text file should be like this  :

    <ns0:Root xmlns:ns0="http://PayrollGLToInterface.InputSchemaWithMultipleHeader_2">
     <Header>
      <Header_Child1>SS</Header_Child1> 
      <Header_Child2>1100</Header_Child2> 
      <Header_Child3>07/21/2015</Header_Child3> 
      <Header_Child4>7/31/2015</Header_Child4> 
      <Header_Child5>USD</Header_Child5> 
      <Header_Child6>AA23-06/06/2015</Header_Child6> 
      </Header>
     <Details>
      <Details_Child1>40</Details_Child1> 
      <Details_Child2>122015</Details_Child2> 
      <Details_Child3>105655.19</Details_Child3> 
      <Details_Child4>AA032015</Details_Child4> 
      <Details_Child5>20100</Details_Child5> 
      <Details_Child6>3001</Details_Child6> 
      <Details_Child7>7005339800</Details_Child7> 
      </Details>
     <Details>
      <Details_Child1>50</Details_Child1> 
      <Details_Child2>122015</Details_Child2> 
      <Details_Child3>105655.19</Details_Child3> 
      <Details_Child4>AA032015</Details_Child4> 
      <Details_Child5>20100</Details_Child5> 
      <Details_Child6>3001</Details_Child6> 
      <Details_Child7>7005339800</Details_Child7>  
      </Details>
    <Header>
      <Header_Child1>BB</Header_Child1> 
      <Header_Child2>1200</Header_Child2> 
      <Header_Child3>07/21/2015</Header_Child3> 
      <Header_Child4>7/31/2015</Header_Child4> 
      <Header_Child5>USD</Header_Child5> 
      <Header_Child6>AA03-06/06/2015</Header_Child6> 
      </Header>
    <Details>
      <Details_Child1>40</Details_Child1> 
      <Details_Child2>132015</Details_Child2> 
      <Details_Child3>105655.19</Details_Child3> 
      <Details_Child4>AA032015</Details_Child4> 
      <Details_Child5>20100</Details_Child5> 
      <Details_Child6>3001</Details_Child6> 
      <Details_Child7>7005339800</Details_Child7> 
      </Details>
     <Details>
      <Details_Child1>50</Details_Child1> 
      <Details_Child2>132015</Details_Child2> 
      <Details_Child3>105655.19</Details_Child3> 
      <Details_Child4>AA032015</Details_Child4> 
      <Details_Child5>20100</Details_Child5> 
      <Details_Child6>3001</Details_Child6> 
      <Details_Child7>7005339800</Details_Child7>  
      </Details>
      </ns0:Root>

    Is it possible to create such output through flat file disassembler?


    Prakash


    • Edited by Shivay_ Thursday, August 13, 2015 12:33 PM
    Thursday, August 13, 2015 12:32 PM

Answers

  • Hi PKS,

    Below is detailed steps for implementation, it may helps others also.

    1) You can use Pipeline Component in decode stage

            - Prepare a copy of the message, which shows header, details (will be used as tag identifiers for schema creation) as shown below, create a schema for the same sample using Tag Identifiers (H,D). 
    - Pipeline Component Decode Stage: Update the message with header, Details based on your logic, return the updated message.
            - Then disassemble the message with default Flat file disassembler, specifying the document schema, which you created above.
            - Drop the original message, that process as expected .

    2) You can do the same steps in Custom Flat File disassembler, then disassemble the message with the schema.

    The below detailed information is for 1st approach custom decode pipeline component.

    FFSchemaHeaderDetails

    #region IComponent members
            /// <summary>
            /// Implements IComponent.Execute method.
            /// </summary>
            /// <param name="pContext">Pipeline context</param>
            /// <param name="pInMsg">Input message</param>
            /// <returns>Original input message</returns>
            /// <remarks>
            /// IComponent.Execute method is used to initiate
            /// the processing of the message in this pipeline component.
            /// </remarks>
    
            public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(Microsoft.BizTalk.Component.Interop.IPipelineContext pContext, Microsoft.BizTalk.Message.Interop.IBaseMessage pInMsg)
            {
                try
                {
                    StreamReader streamReader = new StreamReader(pInMsg.BodyPart.GetOriginalDataStream());
                    StringBuilder sb = new StringBuilder();
                    string[] lines = streamReader.ReadToEnd().ToString().Split(new string[] { ("\r\n") }, StringSplitOptions.None);
                    foreach (var line in lines)
                    {
                        if (line.Split(',').Count() == 6)
                        {
                            sb.Append("H," + line + "\r\n");
                        }
                        if (line.Split(',').Count() == 7)
                        {
                            sb.Append("D," + line + "\r\n");
                        }
                    }
                    byte[] bytesString = Encoding.UTF8.GetBytes(sb.ToString());
                    streamReader.Close();
                    MemoryStream OutmemoryStream = new MemoryStream();
                    OutmemoryStream.Write(bytesString, 0, bytesString.Length);
                    OutmemoryStream.Seek(0, SeekOrigin.Begin);
                    pInMsg.BodyPart.Data = OutmemoryStream;
                    pContext.ResourceTracker.AddResource(OutmemoryStream);
                    return pInMsg;
                }
                catch (Exception)
                {
                    throw;
                }
            }
            #endregion
    Let us know if you need any further information on this.


    Thanks, SMSVikasK

    • Proposed as answer by Aurel Bera Tuesday, August 18, 2015 2:39 PM
    • Marked as answer by Angie Xu Monday, August 24, 2015 1:37 AM
    Tuesday, August 18, 2015 7:54 AM
    Answerer

All replies

  • I think you'll struggle with identifying by number of fields, I have another post active currently due to the flat-file disassembler merging extra fields into the last column of the shorter list.  So far, I haven't worked around this.

    If your header starts with a predictable value you can use tags to identify the row.


    If this is helpful or answers your question - please mark accordingly.
    Because I get points for it which gives my life purpose (also, it helps other people find answers quickly)

    Thursday, August 13, 2015 1:07 PM
  • Hi,

    I can see 2 approaches for this as of now:

    • As suggested by Alastair, if the header can be identified with a particluar tag, then you can use the "Tag Identifier" property on the node to identify the node.
    • If the Header cannot be defined with some specfic tag, then you can have a custom pipeline code to get the correct structure.

    Regards,

    Rahul

    Thursday, August 13, 2015 1:15 PM
  • Hi,

    According to your schema there is no tag Identifier,because your header lines are being changed.

    You should write your custom disassemble code that count each row value and generate record based on value is 6 or 7.


    If this post is helpful, please vote as helpful or marked as answer.

    Thursday, August 13, 2015 1:29 PM
  • Hi PKS,

    Below is detailed steps for implementation, it may helps others also.

    1) You can use Pipeline Component in decode stage

            - Prepare a copy of the message, which shows header, details (will be used as tag identifiers for schema creation) as shown below, create a schema for the same sample using Tag Identifiers (H,D). 
    - Pipeline Component Decode Stage: Update the message with header, Details based on your logic, return the updated message.
            - Then disassemble the message with default Flat file disassembler, specifying the document schema, which you created above.
            - Drop the original message, that process as expected .

    2) You can do the same steps in Custom Flat File disassembler, then disassemble the message with the schema.

    The below detailed information is for 1st approach custom decode pipeline component.

    FFSchemaHeaderDetails

    #region IComponent members
            /// <summary>
            /// Implements IComponent.Execute method.
            /// </summary>
            /// <param name="pContext">Pipeline context</param>
            /// <param name="pInMsg">Input message</param>
            /// <returns>Original input message</returns>
            /// <remarks>
            /// IComponent.Execute method is used to initiate
            /// the processing of the message in this pipeline component.
            /// </remarks>
    
            public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(Microsoft.BizTalk.Component.Interop.IPipelineContext pContext, Microsoft.BizTalk.Message.Interop.IBaseMessage pInMsg)
            {
                try
                {
                    StreamReader streamReader = new StreamReader(pInMsg.BodyPart.GetOriginalDataStream());
                    StringBuilder sb = new StringBuilder();
                    string[] lines = streamReader.ReadToEnd().ToString().Split(new string[] { ("\r\n") }, StringSplitOptions.None);
                    foreach (var line in lines)
                    {
                        if (line.Split(',').Count() == 6)
                        {
                            sb.Append("H," + line + "\r\n");
                        }
                        if (line.Split(',').Count() == 7)
                        {
                            sb.Append("D," + line + "\r\n");
                        }
                    }
                    byte[] bytesString = Encoding.UTF8.GetBytes(sb.ToString());
                    streamReader.Close();
                    MemoryStream OutmemoryStream = new MemoryStream();
                    OutmemoryStream.Write(bytesString, 0, bytesString.Length);
                    OutmemoryStream.Seek(0, SeekOrigin.Begin);
                    pInMsg.BodyPart.Data = OutmemoryStream;
                    pContext.ResourceTracker.AddResource(OutmemoryStream);
                    return pInMsg;
                }
                catch (Exception)
                {
                    throw;
                }
            }
            #endregion
    Let us know if you need any further information on this.


    Thanks, SMSVikasK

    • Proposed as answer by Aurel Bera Tuesday, August 18, 2015 2:39 PM
    • Marked as answer by Angie Xu Monday, August 24, 2015 1:37 AM
    Tuesday, August 18, 2015 7:54 AM
    Answerer