Injecting your own X12 specification

Though I would hope you would want to submit your specifications for inclusion in the open source (I will mention your name and company on the documentation for your contribution), there might be reasons that you might want to maintain your own specifications, but be able to update versions of the OopFactory.X12.dll without losing your work. Some of these reasons might be:

  1. Your company has different descriptions for loops or elements that you want displayed on the html view. This is especially true for some loops that just have a loop ID of NM1 which isn't very descriptive.
  2. You have a specific agreement with a trading partner that uses slightly modified specifications per a companion guide that you have agreed upon.
  3. You have spotted a bug in the embedded specifications and would like to fix it externally to the assembly while you wait for the next update with the fix.
  4. You absolutely love X12 so much that you are using it for persistence of objects that are not part of the X12 standard sets. :-)


In any of the above cases you would want to be able to use your own specification that is outside the OopFactory.X12 assembly. Let's look at how that can be done.  The completed solution can be downloaded here.

Implement ISpecificationFinder by Overriding SpecificationFinder

By default, OopFactory.X12.Parsing.X12Parser uses OopFactory.X12.Parsing.SpecificationFinder which will load the embedded XML specifications based on the version and transaction code in the GS and ST segments respectively. You selective choose to override which specification to use creating your own derived class of SpecificationFinder.

1.  Create a new console application and reference the OopFactory.X12.dll.

2.  Add your custom specification.  In this example I use the 997 for brievity:

 

<?xml version="1.0" encoding="utf-8" ?>
<TransactionSpecification xmlns="http://tempuri.org/X12ParserSpecification.xsd"  TransactionSetIdentifierCode="997">
  <Segment SegmentId="AK1"/>
  <Segment SegmentId="AK9" Trailer="true"/>
  <Loop LoopId="AK2" Usage="Required" LoopRepeat="999999">
    <Name></Name>
    <StartingSegment SegmentId="AK2" Usage="Required" Repeat="1"/>
    <Segment SegmentId="AK5" Trailer="true"/>
    <Loop LoopId="AK2/AK3" Usage="Required" LoopRepeat="999999">
      <Name>PAYER IDENTIFICATION</Name>
      <StartingSegment SegmentId="AK3" Usage="Required" Repeat="1"/>
      <Segment SegmentId="AK4" Usage="Required" Repeat="99"/>
    </Loop>
  </Loop>
</TransactionSpecification>

The class model for the specification is as follows:

Specification Model

3.  Change the file properties Build Action = "Embedded Resource".

4.  Add a new class to inherit from SpecificationFinder:

 

using System;
using System.IO;
using System.Reflection;
using OopFactory.X12.Parsing;
using OopFactory.X12.Parsing.Specification;

namespace MyCustomParser
{
    public class MySpecificationFinder : SpecificationFinder
    {
        public override OopFactory.X12.Parsing.Specification.TransactionSpecification FindTransactionSpec(string functionalCode, string versionCode, string transactionSetCode)
        {
            if (transactionSetCode == "997")
            {
                Stream specStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MyCustomParser.My997Spec.xml");
                return TransactionSpecification.Deserialize(new StreamReader(specStream).ReadToEnd());
            }
            else
                return base.FindTransactionSpec(functionalCode, versionCode, transactionSetCode);
        }
    }
}

 

5.  Inject your custom specification finder into the X12Parser:

 

using System;
using System.IO;
using OopFactory.X12.Parsing;

namespace MyCustomParser
{
    class Program
    {
        static void Main(string[] args)
        {
            string x12Filename = args[0];
            string outputFilename = args.Length > 1 ? args[1] : x12Filename + ".xml";

            FileStream fs = new FileStream(x12Filename, FileMode.Open);
            OopFactory.X12.Parsing.X12Parser parser = new X12Parser(new MySpecificationFinder());
            string xml = parser.Parse(fs).Serialize();
            fs.Close();

            FileStream outputFs = new FileStream(outputFilename, FileMode.Create);
            StreamWriter writer = new StreamWriter(outputFs);
            writer.Write(xml);
            writer.Close();
        }
    }
}

Last edited Jun 25, 2011 at 6:16 PM by dstrubhar, version 7

Comments

rebwal82 Jul 16, 2014 at 4:12 PM 
Did you figure out how to generate 997s for POs? I used the acknowledgetransactions, but it created a 999 not a 997 :/

AnthonyPeiris Jul 13, 2014 at 2:03 PM 
How do I generate 997 for inbound po 850 ?