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:
- 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.
- You have a specific agreement with a trading partner that uses slightly modified specifications per a companion guide that you have agreed upon.
- 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.
- 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
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="AK9" Trailer="true"/>
<Loop LoopId="AK2" Usage="Required" LoopRepeat="999999">
<StartingSegment SegmentId="AK2" Usage="Required" Repeat="1"/>
<Segment SegmentId="AK5" Trailer="true"/>
<Loop LoopId="AK2/AK3" Usage="Required" LoopRepeat="999999">
<StartingSegment SegmentId="AK3" Usage="Required" Repeat="1"/>
<Segment SegmentId="AK4" Usage="Required" Repeat="99"/>
The class model for the specification is as follows:
3. Change the file properties Build Action = "Embedded Resource".
4. Add a new class to inherit from SpecificationFinder:
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());
return base.FindTransactionSpec(functionalCode, versionCode, transactionSetCode);
5. Inject your custom specification finder into the X12Parser:
static void Main(string args)
string x12Filename = args;
string outputFilename = args.Length > 1 ? args : x12Filename + ".xml";
FileStream fs = new FileStream(x12Filename, FileMode.Open);
OopFactory.X12.Parsing.X12Parser parser = new X12Parser(new MySpecificationFinder());
string xml = parser.Parse(fs).Serialize();
FileStream outputFs = new FileStream(outputFilename, FileMode.Create);
StreamWriter writer = new StreamWriter(outputFs);