Giter Site home page Giter Site logo

edi.net's Introduction

EDI.Net alt text

Build status NuGet Downloads

EDI Serializer/Deserializer. Used to read & write EDI streams.

This is a ground up implementation and does not make use of XML Serialization in any step of the process. This reduces the overhead of converting into multiple formats allong the way of getting the desired Clr object. This makes the process quite fast.

Tested with Tradacoms, EDIFact and ANSI ASC X12 (X12) formats.

Using attributes you can express all EDI rules like Mandatory/Conditional Segments, Elements & Components as well as describe component values size length and precision with the picture syntax (e.g 9(3), 9(10)V9(2) and X(3)).

Quick links

Installation

To install Edi.Net, run the following command in the Package Manager Console. Or download it here

PM> Install-Package "indice.Edi"

Attributes.

The general rules of thumb are :

Attribute Description
EdiValue Any value inside a segment. (ie the component value 500 in bold)
UCI+001342651817+9907137000005:500+9912022000002:500+7
EdiElement Elements are considered to be groups of values otherwise known as groups of components. One can use this attribute to deserialize into a complex class that resides inside a segment. For example this can usually be used to deserialize more than one value between + into a ComplexType (ie the whole element into a new class 9912022000002:500 in bold)
UCI+001342651817+9907137000005:500+9912022000002:500+7
EdiPath To specify the path
EdiSegment Marks a propery/class to be deserialized for a given segment. Used in conjunction with EdiPath
EdiSegmentGroup Marks a propery/class as a logical container of segments. This allows a user to decorate a class whith information regarding the starting and ending segments that define a virtual group other than the standard ones (Functional Group etc). Can be applied on Lists the same way that [Message] or [Segment] attributes work
EdiMessage Marks a propery/class to be deserialized for any message found.
EdiGroup Marks a propery/class to be deserialized for any group found.
EdiCondition In case multiple MessageTypes or Segment types with the same name. Used to discriminate the classes based on a component value

Example usage:

There are available configurations (EdiGrammar) for EDIFact, Tradacoms and X12. Working examples for all supported EDI formats can be found in the source code under tests.

Note that all examples may be partialy implemented transmissions for demonstration purposes although they are a good starting point. If someone has complete poco classes for any transmition please feel free to contribute a complete test.

Deserialization (EDI to POCOs)

The following example makes use of the Tradacoms grammar and deserializes the sample.edi file to the Interchange class.

var grammar = EdiGrammar.NewTradacoms();
var interchange = default(Interchange);
using (var stream = new StreamReader(@"c:\temp\sample.edi")) {
    interchange = new EdiSerializer().Deserialize<Interchange>(stream, grammar);
}

Serialization (POCOs to EDI)

In this case we are instantiating our POCO class Interchange and then fill-it up with values before finally serializing to out.edi.

var grammar = EdiGrammar.NewTradacoms();
var interchange = new Interchange();
// fill properies 
interchange.TransmissionDate = DateTime.Now;
...
// serialize to file.
using (var textWriter = new StreamWriter(File.Open(@"c:\temp\out.edi", FileMode.Create))) {
    using (var ediWriter = new EdiTextWriter(textWriter, grammar)) { 
        new EdiSerializer().Serialize(ediWriter, interchange);
    }
}

Model

Annotated POCOS example using part of Tradacoms UtilityBill format:

public class Interchange
{
    [EdiValue("X(14)", Path = "STX/1/0")]
    public string SenderCode { get; set; }

    [EdiValue("X(35)", Path = "STX/1/1")]
    public string SenderName { get; set; }

    [EdiValue("9(6)", Path = "STX/3/0", Format = "yyMMdd", Description = "TRDT - Date")]
    [EdiValue("9(6)", Path = "STX/3/1", Format = "HHmmss", Description = "TRDT - Time")]
    public DateTime TransmissionStamp { get; set; }

    public InterchangeHeader Header { get; set; }

    public InterchangeTrailer Trailer { get; set; }

    public List<UtilityBill> Invoices { get; set; }
}

[EdiMessage, EdiCondition("UTLHDR", Path = "MHD/1")]
public class InterchangeHeader
{
    [EdiValue("9(4)"), EdiPath("TYP")]
    public string TransactionCode { get; set; }

    [EdiValue("9(1)", Path = "MHD/1/1")]
    public int Version { get; set; }
}

[EdiMessage, EdiCondition("UTLTLR", Path = "MHD/1")]
public class InterchangeTrailer
{

    [EdiValue("9(1)", Path = "MHD/1/1")]
    public int Version { get; set; }
}

[EdiMessage, EdiCondition("UTLBIL", Path = "MHD/1")]
public class UtilityBill
{
    [EdiValue("9(1)", Path = "MHD/1/1")]
    public int Version { get; set; }

    [EdiValue("X(17)", Path = "BCD/2/0", Description = "INVN - Date")]
    public string InvoiceNumber { get; set; }

    public MetetAdminNumber Meter { get; set; }
    public ContractData SupplyContract { get; set; }

    [EdiValue("X(3)", Path = "BCD/5/0", Description = "BTCD - Date")]
    public BillTypeCode BillTypeCode { get; set; }

    [EdiValue("9(6)", Path = "BCD/1/0", Format = "yyMMdd", Description = "TXDT - Date")]
    public DateTime IssueDate { get; set; }

    [EdiValue("9(6)", Path = "BCD/7/0", Format = "yyMMdd", Description = "SUMO - Date")]
    public DateTime StartDate { get; set; }

    [EdiValue("9(6)", Path = "BCD/7/1", Format = "yyMMdd", Description = "SUMO - Date")]
    public DateTime EndDate { get; set; }

    public UtilityBillTrailer Totals { get; set; }
    public UtilityBillValueAddedTax Vat { get; set; }
    public List<UtilityBillCharge> Charges { get; set; }

    public override string ToString() {
        return string.Format("{0} TD:{1:d} F:{2:d} T:{3:d} Type:{4}", InvoiceNumber, IssueDate, StartDate, EndDate, BillTypeCode);
    }
}

[EdiSegment, EdiPath("CCD")]
public class UtilityBillCharge
{
    [EdiValue("9(10)", Path = "CCD/0")]
    public int SequenceNumber { get; set; }

    [EdiValue("X(3)", Path = "CCD/1")]
    public ChargeIndicator? ChargeIndicator { get; set; }

    [EdiValue("9(13)", Path = "CCD/1/1")]
    public int? ArticleNumber { get; set; }

    [EdiValue("X(3)", Path = "CCD/1/2")]
    public string SupplierCode { get; set; }

    [EdiValue("9(10)V9(3)", Path = "CCD/10/0", Description = "CONS")]
    public decimal? UnitsConsumedBilling { get; set; }
}

Contributions

The following is a set of guidelines for contributing to EDI.Net.

Did you find a bug?
  • Ensure the bug was not already reported by searching on GitHub under Issues.
  • If you're unable to find an open issue addressing the problem, open a new one. Be sure to include a title and clear description, as much relevant information as possible, and a code sample or an executable test case demonstrating the expected behavior that is not occurring.
Did you write a patch that fixes a bug?

Open a new GitHub pull request with the patch. Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable.

Build the sourcecode

As of v1.0.7 the solution was adapted to support the dotnet core project system. Then it was adapted again since the dotnet core tooling was officialy relased (March 7th 2017 at the launch of Visual studio 2017). In order to build and test the source code you will need either one of the following.

  • Visual studio 2017 + the dotnet core workload (for v1.1.3 onwards)
  • Visual studio 2015 Update 3 & .NET Core 1.0.0 - VS 2015 Tooling (for versions v1.0.7 - v1.1.2)
  • VS Code + .NET Core SDK

for more information check .Net Core official page.

The Picture clause

The Picture Clause is taken from COBOL laguage and the way it handles expressing numeric and alphanumric data types. It is used throughout tradacoms.

Symbol Description Example Picture Component c# result
9 Numeric 9(3) 013 int v = 13;
A Alphabetic not used - -
X Alphanumeric X(20) This is alphanumeric string v = "This is alphanumeric";
V Implicit Decimal 9(3)V9(2) 01342 decimal v = 13.42M;
S Sign not used - -
P Assumed Decimal not used - -

Roadmap (TODO)

  • Implement serializer Serialize to write Clr classes to edi format (Using attributes). (planned for v1.1)
  • Start github wiki page and begin documentation.
  • Create a seperate package (or packages per EDI Format) to host well known interchange transmitions (ie Tradacoms Utitlity Bill). Then anyone can fork and contribute his own set of POCO classes.

Disclaimer. The project was inspired and influenced by the work done in the excellent library JSON.Net by James Newton King. Some utility parts for reflection string parsing etc. are used as is

edi.net's People

Contributors

cleftheris avatar cwhellams avatar dfyx avatar drenalol avatar drwhalen avatar eddyrodrigues avatar gingerninjaa avatar gk7gk7 avatar gvg avatar h0gh avatar koosbusters avatar laggat avatar maximeshift avatar mb512 avatar michaelachrisco avatar nekeniehl avatar richardwalenga avatar sylwesterzarebski avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

edi.net's Issues

Omitting blank segments when serializing?

Hello all, I have a rather simple question, my model has some segments that are optional for example in this example (N3, N4) are optional address information segments:

...
DTP***20110201~
N3**~
N4****~
SE*50*~
...

Is there a way to make the serializer ignore these when generating my file or is this something I would have to do on my own?

Here is an example of the output I would be going for:

...
DTP***20110201~
SE*50*~
...

EdiSegmentGroup not parsing the whole Segment

Hi there, I'm not sure if this is a bug or a bad using of EdiAttributes from my side. I have created a EdiSegmentGroup to parse to a complex type, the segment is called "SG1" which basically contains a RFF (code and qualifier) and a optional DTM(code, date, format). I have made almost the same structure with the NAD segment which is actually working fine, but not for the SG1. Here the structure I want to follow

2017-04-04_15-09-21

Here a Test Message:

UNA:+.? 'UNB+UNOC:3+9900080000007:500+990000000000X:500+160321:1425+DAREFNR0000001'UNH+9IMX20YSP0009+ORDRSP:D:10A:UN:1.1e'BGM+Z12+IM20U000000000CNF'DTM+137:201603211421:203'IMD++Z14+Z07'DTM+203:20151023:102'DTM+Z02:20110408:102'IMD++Z01'IMD++Z10'IMD++Z14+Z06'RFF+ON:00001672'DTM+171:201510231149:203'RFF+Z13:19101'AJT+Z15'NAD+MS+9900080000007::293'CTA+IC+:Spiderman, Clark'COM+?+49 123 456 8652:TE'[email protected]:EM'NAD+MR+990000000000X::293'NAD+DP'LOC+172+DE12345610243DE0000000000000XXXXX'CUX+2:EUR:9'LIN+1++9900010000649:Z01'QTY+145:1:PCS'MOA+203:825'FTX+ACB+++Text1:Text2:Text3:Text4:Text5'PRI+CAL:50.5'RFF+Z09:8465929523'RFF+Z06:7'UNS+S'MOA+24:9'UNT+17+9IM20YSP9'UNZ+1+DAREFNR00001'

And here the POCO Class (Not completed)

public class ORDRSP : FormatBase
    {
        private List<Nachricht> _listnachricht;

        #region Properties

        public List<Nachricht> ListNachricht
        {
            get { return _listnachricht; }
            set { _listnachricht = value; }
        }

        #endregion

        #region Nested type: CTA

        [EdiPath("CTA[0][0]")]
        [EdiSegment]
        public class CTA
        {
            private string _funktion;

            private string _kontakt;

            private string _kontaktnummer;

            #region Properties

            [EdiValue("X(3)", "CTA/0/0")]
            public string Funktion
            {
                get { return _funktion; }
                set { _funktion = value; }
            }

            [EdiValue("X(17)", "CTA/1/0")]
            public string Kontaktnummer
            {
                get { return _kontaktnummer; }
                set { _kontaktnummer = value; }
            }

            [EdiValue("X(0)", "CTA/1/1")]
            public string Kontakt
            {
                get { return _kontakt; }
                set { _kontakt = value; }
            }

            #endregion
        }

        #endregion

        #region Nested type: DTM

        [EdiSegment]
        [EdiPath("DTM[0][0]")]
        public class DTM
        {
            private string _code;

            private string _datum;

            private string _format;

            #region Properties

            [EdiValue("X(3)", "DTM/0/0")]
            public string Code
            {
                get { return _code; }
                set { _code = value; }
            }

            [EdiValue("X(35)", "DTM/0/1")]
            public string Datum
            {
                get { return _datum; }
                set { _datum = value; }
            }

            [EdiValue("X(3)", "DTM/0/2")]
            public string Format
            {
                get { return _format; }
                set { _format = value; }
            }

            #endregion
        }

        #endregion

        #region Nested type: Nachricht

        [EdiMessage]
        public class Nachricht
        {
            private NAD _absender;
            private NAD _empfaenger;

            #region Properties

            [EdiCondition("MR", "NAD[0][0]")]
            public NAD Empfaenger
            {
                get { return _empfaenger; }
                set { _empfaenger = value; }
            }

            [EdiCondition("MS", "NAD[0][0]")]
            public NAD Absender
            {
                get { return _absender; }
                set { _absender = value; }
            }

            [EdiCondition("ON", "RFF[0][0]")]
            public SG1 Referenz_der_Anfrage { get; set; }
            #endregion
        }

        #endregion

        #region Nested type: NAD

        [EdiSegmentGroup("NAD[0][0]")]
        public class NAD
        {
            private string _code;

            private CTA _cta;

            private string _id;
            private string _qualifier;

            #region Properties

            [EdiValue("X(3)", "NAD/0/0")]
            public string Qualifier
            {
                get { return _qualifier; }
                set { _qualifier = value; }
            }

            [EdiValue("X(35)", "NAD/1/0")]
            public string ID
            {
                get { return _id; }
                set { _id = value; }
            }

            [EdiValue("X(3)", "NAD/1/2")]
            public string Code
            {
                get { return _code; }
                set { _code = value; }
            }

            public CTA CTA
            {
                get { return _cta; }
                set { _cta = value; }
            }

            #endregion
        }

        #endregion

        #region Nested type: SG1

        [EdiSegmentGroup("RFF")]
        public class SG1
        {
            private RFF _referenz;

            private DTM _referenzDatum;

            #region Properties

            //[EdiCondition("ON", "RFF[0][0]")]
            public RFF ReferenzderAnfrage
            {
                get { return _referenz; }
                set { _referenz = value; }
            }

            //[EdiCondition("171", "DTM[0][0]")]
            public DTM Referenz_der_Anfragedatum
            {
                get { return _referenzDatum; }
                set { _referenzDatum = value; }
            }

            #endregion
        }

        #endregion

        #region Nested type: RFF

        [EdiSegment]
        [EdiPath("RFF[0][0]")]
        public class RFF
        {
            private string _code;

            private string _qualifier;

            #region Properties

            [EdiValue("X(70)", "RFF/0/0")]
            public string Code
            {
                get { return _code; }
                set { _code = value; }
            }

            [EdiValue("X(3)", "RFF/0/1")]
            public string Qualifier
            {
                get { return _qualifier; }
                set { _qualifier = value; }
            }

            #endregion
        }

        #endregion
    }

I have try with several different configurations without success, like it is now, you will get parsed the both NAD's and SG1 date but not the reference.

I also tried to add the following lines in the Nachricht class and is working fine everything, but I think is not the correct structure since the DTM is dependent (or child) for the RFF

[EdiCondition("ON", "RFF[0][0]")]
public RFF ReferenzderAnfrage { get; set; }

[EdiCondition("171", "DTM[0][0]")]
public DTM Referenz_der_Anfragedatum { get; set; }

Hope you can help me out, thanks in advance!

How to define my POCO?

I'm new to parse edi.I have a edi doc like below:

00:IFTMBF:BOOKING:9:XXXX:SINOTRANS:20090530:2.0'
02:XXXXBOOKING-0002:BLNO002:CY/CY::::::::::::SCNO'
03:1:CNSHA:SHANGHAI::3:CNSHA:CNSHA'
11::VESSEL:VOYAGE:SNL::SNL::20090630:::::'
12:CNCKG:CHONGQING:CNSHA:SHANGHAI:JPTYO:TOKYO:SGSIN:SINGAPORE:USNYC:NEW YORK:CNTAO:QINGDAO:'
14:PP: FREIGHT PREPAID'
15::FEEMEMO:PP:'
17:REMARK1:REMARK2:REMARK3:REMARK4:REMARK5'
18::SHNAME:SHADDR
TEL
FAX'
19::CONAME:COADDR
TEL
FAX'
20::NONAME:NOADDR
TEL
FAX'
21::NO2NAME'
40:40GP:1:L:XXXXBOOKING-0001::::Y:1::'
41:1:HSCODE:S:1:HYBG:BAG:2:3.000:2:HYBG:BAGS:3:4:8:9:J:JYN:100:2:CN'
43:CLS:PAGE:UNNO:LABEL:FP:EMS:MFAG:Y:EME:100:C:1:2:3:1:2:3:4:5:DANAME:DATEL:DAMAIL:DAFAX'
44:MARKS:::::'
47:CARGODESC:::::'
51:SNTU4014628:40GP:SEAL:E::F:1:8:9:3'
99:19'

I try NewEdiFact to deserialize, but get error, the document does not have a segment name '+'.
so what can i do? to defined a new EdiGrammar or maybe my pojo is not right?
can you please give me some suggestion, thank you very much

Design a logo

Browsing the internet I found some cool illustrations of punchcard logos. So I though I'd choose the punch-card as the logo for Edi.Net since they both have a "retro" feeling about them.

I will post again with what I came up with.

Trouble With Some X.12

This isn't an issue with the library - but I need some guidance.

I have a 214 (Transportation) with a loop of places

ISA*00*          *00*          *02*SCAC           *ZZ*MGCTLYST       
*160726*1303*U*00403*000082265*0*T*>~
GS*QM*SCAC*MGCTLYST*20160726*1303*82265*X*004030~
ST*214*822650001~
B10*1751807*75027674*SCAC~
N1*SH*CATALYST PAPER (USA) INC~
N3*DUMP ROAD~
N4*RUMFORD*ME*04276~
N1*CN*FIBERMARK, INC~
N3*161 WELLINGTON ROAD~
N4*BRATTLEBORO*VT*05301~
N1*BT*CATALYST PAPER~
N3*1 DUMP ROAD~
N4*RUMFORD*ME*04276~
LX*1~
AT7*D1*NS***20160726*1230*LT~
MS1*BRATTLEBORO*VT~
MS2*SCAC*30402~
SE*16*822650001~
GE*1*82265~
IEA*1*000082265~

I have the ISA and functional group working just fine, I have the ST within a message in the functional group GS. From there I can't figure out how to get the rest of the file going starting with B10 and the N loops.

Code I have this far:

    class Program
    {
        static void Main(string[] args)
        {
            var grammar = EdiGrammar.NewX12();
            using (var stream = new StreamReader(@"C:\sandbox\drdispatch\EDI\assets\214-MGCTLYST-SAMPLE.EDI"))
            {
                var interchange = new EdiSerializer().Deserialize<Interchange>(stream, grammar);
                Console.WriteLine($"Receiver Id: {interchange.Receiver_ID}");
                Console.WriteLine("--Groups");
                foreach (var group in interchange.Groups)
                {
                    Console.WriteLine("----Messages");
                    foreach (var msg in group.Messages)
                    {

                        Console.WriteLine($"ID Code {msg.IdentifierCode}");
                        Console.WriteLine($"Control # {msg.ControlNumber}");
                    }
                }

                Console.ReadKey();  
            }
        }
    }

    public class Interchange
    {
        [EdiValue("9(2)", Path = "ISA/0", Description = "I01 - Authorization Information Qualifier")]
        public int AuthorizationInformationQualifier { get; set; }
        [EdiValue("X(10)", Path = "ISA/1", Description = "")]
        public string AuthorizationInformation { get; set; }
        [EdiValue("9(2)", Path = "ISA/2", Description = "I03 - Security Information Qualifier")]
        public string Security_Information_Qualifier { get; set; }

        [EdiValue("X(10)", Path = "ISA/3", Description = "I04 - Security Information")]
        public string Security_Information { get; set; }

        [EdiValue("9(2)", Path = "ISA/4", Description = "I05 - Interchange ID Qualifier")]
        public string ID_Qualifier { get; set; }

        [EdiValue("X(15)", Path = "ISA/5", Description = "I06 - Interchange Sender ID")]
        public string Sender_ID { get; set; }

        [EdiValue("9(2)", Path = "ISA/6", Description = "I05 - Interchange ID Qualifier")]
        public string ID_Qualifier2 { get; set; }

        [EdiValue("X(15)", Path = "ISA/7", Description = "I07 - Interchange Receiver ID")]
        public string Receiver_ID { get; set; }

        [EdiValue("9(6)", Path = "ISA/8", Format = "yyMMdd", Description = "I08 - Interchange Date")]
        [EdiValue("9(4)", Path = "ISA/9", Format = "HHmm", Description = "TI09 - Interchange Time")]
        public DateTime Date { get; set; }

        [EdiValue("X(1)", Path = "ISA/10", Description = "I10 - Interchange Control Standards ID")]
        public string Control_Standards_ID { get; set; }

        [EdiValue("9(5)", Path = "ISA/11", Description = "I11 - Interchange Control Version Num")]
        public int ControlVersion { get; set; }

        [EdiValue("9(9)", Path = "ISA/12", Description = "I12 - Interchange Control Number")]
        public int ControlNumber { get; set; }

        [EdiValue("9(1)", Path = "ISA/13", Description = "I13 - Acknowledgement Requested")]
        public bool? AcknowledgementRequested { get; set; }

        [EdiValue("X(1)", Path = "ISA/14", Description = "I14 - Usage Indicator")]
        public string Usage_Indicator { get; set; }

        [EdiValue("X(1)", Path = "ISA/15", Description = "I15 - Component Element Separator")]
        public char? Component_Element_Separator { get; set; }
        [EdiValue("9(1)", Path = "IEA/0", Description = "I16 - Num of Included Functional Grps")]
        public int GroupsCount { get; set; }

        [EdiValue("9(9)", Path = "IEA/1", Description = "I12 - Interchange Control Number")]
        public int TrailerControlNumber { get; set; }

        public List<FunctionalGroup> Groups { get; set; }

        [EdiGroup]
        public class FunctionalGroup
        {
            [EdiValue("X(2)", Path = "GS/0", Description = "479 - Functional Identifier Code")]
            public string FunctionalIdentifierCode { get; set; }

            [EdiValue("X(15)", Path = "GS/1", Description = "142 - Application Sender's Code")]
            public string ApplicationSenderCode { get; set; }

            [EdiValue("X(15)", Path = "GS/2", Description = "124 - Application Receiver's Code")]
            public string ApplicationReceiverCode { get; set; }

            [EdiValue("9(8)", Path = "GS/3", Format = "yyyyMMdd", Description = "373 - Date")]
            [EdiValue("9(4)", Path = "GS/4", Format = "HHmm", Description = "337 - Time")]
            public DateTime Date { get; set; }

            [EdiValue("9(9)", Path = "GS/5", Format = "HHmm", Description = "28 - Group Control Number")]
            public int GroupControlNumber { get; set; }

            [EdiValue("X(2)", Path = "GS/6", Format = "HHmm", Description = "455 Responsible Agency Code")]
            public string AgencyCode { get; set; }

            [EdiValue("X(2)", Path = "GS/7", Format = "HHmm", Description = "480 Version / Release / Industry Identifier Code")]
            public string Version { get; set; }

            public List<Message> Messages { get; set; }

            [EdiValue("9(1)", Path = "GE/0", Description = "97 Number of Transaction Sets Included")]
            public int TransactionsCount { get; set; }

            [EdiValue("9(9)", Path = "GE/1", Description = "28 Group Control Number")]
            public int GroupTrailerControlNumber { get; set; }


        }


        [EdiMessage]
        public class Message
        {
            [EdiValue("9(3)", Path = "ST/00", Description = "")]
            public int IdentifierCode { get; set; }
            [EdiValue("X(9)", Path = "ST/01", Description = "")]
            public string ControlNumber { get; set; }

            [EdiValue("9(30)", Path="B10/0")]
            public int ReferenceIdentification { get; set; }

        }

    }

When I use a condition with path greater than 0 the properies all EdiValue paths preciding are left null.

There is an internal read cache that is used to temporarily store the all the already read values as the reader advances to the next tokens inside the file stream (text buffer). This is called the ReadCache and it is reset whenever the serializer reaches the beginning of the next segment.

The current design introduces the following problem: Although the sole purpose of the readcache is to help serializer make search operations (for conditional deserialization) without loosing any values, a loss may occur because we are advancing the reader and not being able to check the contents of the cache. This is exactly what seems to be happening with multiple condition attributes.

[Q] Segment groups

Hi,

I'm trying to create an POCO structure that matches the way UN/EDIFACT defines its message structure.

They start of with defining the segments that are available:

image
I would want to create an C# class for every segment listed, decorated with an EdiSegment and EdiPath attribute.

After defining all the segments I should create the logical structure of the message, including grouping and nesting:

image

I tried using the EdiSegmentGroup attribute, but it doens't find any segments in the class that is marked with the EdiSegmentGroup. I suspect that it's because the serializer will steps into the segment upon the EdiSegmentGroup after which it will not find the segment again.

Could someone please elaborate in which structure I can build these more or less anonymous segment groups that should only group together other classes decorated with the EdiSegment.

Variable length support

I'm implementing a protocol based on EDIFACT. In the specification of the protocol it is specified on an per element basis if this an fixed or variable length field.

I would be happy to implement this feature and create a pull request, but I'm not sure where this property would go in the current structure where type and length specification are provided by the PICTURE class. The Picture class is provided to the methods in the EdiTextWriter class that add the padding to the written values so adding this property to the Picture class would enable me to switch in this writer's methods to enable or disable padding at that point. As far as I see there is no notion of fixed vs variable length variables in the PICTURE clause notation, therefore this issue might also be related to #23).

Add preset for EDI X12 grammar

Based on the Wikipedia article about EDIFact and X12 similarities plus the article found on edidev.com the X12 format should be already supported. So why not adding an IEdiGrammar preset like the ones we already got.
Something along these lines..

EdiGrammar.NewEdifact();
EdiGrammar.NewTradacoms();
EdiGrammar.NewX12();

Support autogenerated values

Especially handy for EDI serializer. Some Edi types of transmissions have component values usually located in transmission trailers that for example count the number of messages inside the current Group or Interchange. These are used in order for systems to be able to validate the transmission is not tempered with. There are others that count the number of segments inside the message and so on...

It would be nice to have an extra optional property potentially on the EdiValueAttribute to mark the value AutoGenerated (potentially used only when writing) with options

  • ChildrenCount
  • Timestamp
  • Something else I don't know about

EDI x12 856 support

I'm working on adding support for x12 856 files. The problem I'm running into is that the standard seems to support multiple orders per shipment, but there is no guarantee of a distinguishing tag at the beginning/end of an order section. The HL tag is used extensively inside of shipments, orders and packs. In other words it's not unique any particular block type. I think the Condition marker might be my solution, but I'm still figuring out how to use it.

Has anyone tried implementing 856 support/have any ideas about this?

The spec I'm using as a reference is here:
http://www.gentex.com/sites/default/files/EDI%20856%20(Advanced%20Ship%20Notice)%20Specification%20Document.pdf

EdiSegmentGroup not serialised.

First at all I have to say sorry for the bunch of tickets I'm opening lately.

The problem this time is when you have two EdiSegmentGroup in the Message Level, it only parses one:
I have EdiSegmentGroup for RFF and another EdiSegmentGroup for NAD. The problem seems to be in the TryCreateContainer, when the reader reach the NAD point, the stack contains 3 EdiStructure, the EdiSegmentGroup for the RFF, the message and the interchange. The first conditional is true but when reaches the loop for //Nested hierarchy the conditional if (!level.IsGroup) is false on the Message level (where the other EdiSegmentGroup for NAD is) and simply goes out without finding the property.
I don't know if this can help you to know the problem, but testing, and playing around while debugging I jump to the "else" directly from the first conditional and it works, parsing both EdiSegmentGroups.

Thanks once again.

//FIRST CONDITIONAL
if (newContainer == EdiStructureType.SegmentGroup &&
    (stack.Peek().Container >= EdiStructureType.SegmentGroup)) {
    // strict hierarchy
    while (stack.Peek().Container > newContainer) {
        var previous = stack.Pop(); // close this level
    }
    // nested hierarchy
    foreach (var level in stack) {
        if (!level.IsGroup)
            continue; //THIS IS FALSE FOR @MESSAGE
        var groupStart = level.Descriptor.SegmentGroupInfo.StartInternal;
        var sequenceEnd = level.Descriptor.SegmentGroupInfo.SequenceEndInternal;
        if (reader.Value.Equals(groupStart.Segment)) {
            level.Close(); // Close this level
            index = level.Index + 1;
            break;
        } else if (reader.Value.Equals(sequenceEnd.Segment)) {
            level.Close(); // Close this level
            break;
        }
    }
    if (stack.Any(s => s.IsClosed)) {
        var previous = stack.Peek();
        do
            previous = stack.Pop();
        while (!previous.IsClosed);
    }
} else {
     //IF I JUMP DIRECTLY HERE ON THE NAD IT PARSED CORRECTLY
    // strict hierarchy
    while (stack.Peek().Container >= newContainer) {
        var previous = stack.Pop(); // close this level
        if (previous.Container == newContainer)
            index = previous.Index + 1; // seed collection index
    }
}

Missing build environment documentation

EDI.net appears to now be using .net Core (RC2) ?

It would be useful to add some short notes on the development environment required in order to be able to work on and build the source e.g.

  • Visual Studio version
  • External dependencies required e.g. .net Core
  • Any other tools, libraries or NuGet packages expected

If you do not have .net core installed you will get a message such as this, which does not really tell you what the root cause of the problem is - luckily Google will yield the root cause !

The imported project "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\DotNet\Microsoft.DotNet.Props" was not found. Confirm that the path in the declaration is correct, and that the file exists on disk.

reason : NuGet/Home#2616

Make the EdiCondition & EdiValue attributes work together

EdiCondition attribute was originally designed in order to distinguish between different kinds of message types and deserialize accordingly. This functionality could be expanded to work with component values as well. Then someone could conditionally deserialize the same component path to different properties.

Reading multiple element from line item

Hi,

on my ORDRSP I have multiple elements
QTY+113:26:PCE'
DTM+67:20170607:102'
QTY+113:24:PCE'
DTM+67:20170609:102'

How can I read this?

Thanks, best regards,
Rudolf

Whitespace ignored at start of component

The EDIFACT CUSCAR spec splits the FTX-TEXT LITERAL segment up in 5 components of max 70 characters. A split can happen right before a space but the current implementation will remove the first whitespace for all components.

Removing the skipping over whitespace in the EdiTextReader seems to fix this issue without any side-effects (all unit tests, included and my own implementation unit tests, are still successful after the change), but I'm not sure what specification caused the skip to be implemented in the first place, so I cannot verify this scenario.

Allow EdiConditionAttribute to stack that will then be checked with the `OR` logical operator

Currently you can only have exactly one EdiConditionAttribute annotation per property or class. Also there is only one type of condition check: "exact match of a value (Equal Condition)". I have walked through the code and came up with a solution that will allow you to stack EdiConditionAttributes that will then be checked with the OR logical operator.

Then something like this will be able to work:

        [EdiCondition("Z01", Path = "IMD/1/0")]
	[EdiCondition("Z10", Path = "IMD/1/0")] 	
	public List<IMD> IMD_List { get; set; }

        [EdiCondition("", Path = "IMD/1/0")] 	
	public IMD IMD_Other { get; set; }

[Q] Attributes

I have made a POCO for Edifact.CONTRL (German Energy Market, and I will probably do the rest for this market).

But I'm having troubles with the use of the Attributes since I don't really know which is for what, so far I use the following attributes in the POCO

EdiMessage: Which I guess is the start of the message, the UNH Segment (ie UNH+5451674C50D64+CONTRL:D:3:UN:2.0 )
EdiSegment: Any segment in the CONTRL (ie UCI+001342651817+9907137000005:500+9912022000002:500+7)
EdiValue: Any value inside a segment (ie UCI+001342651817+9907137000005:500+9912022000002:500+7
EdiElement: No idea about how to use this one
EdiPath: To specify the path.

Following the next structure for a simple CONTRL:

UNB+UNOC:3+9912022000002:500+9907137000005:500+160602:1849+EAE519A8366D4
    UNH+5451674C50D64+CONTRL:D:3:UN:2.0
        UCI+001342651817+9907137000005:500+9912022000002:500+7
    UNT+3+5451674C50D64
UNZ+1+EAE519A8366D4
UNB
    UNH
        UCI
    UNT
UNZ

We get the following POCO

    [EdiMessage]
    public class CONTRLMessage
    {
        [EdiValue("X(14)", Path = "UNH/0/0")]
        public string NachrichtKey { get; set; }

        [EdiValue("X(6)", Path = "UNH/1/0")]
        public string MessageType { get; set; }

        [EdiValue("X(3)", Path = "UNH/1/1")]
        public string Version { get; set; }

        [EdiValue("X(3)", Path = "UNH/1/2")]
        public string ReleaseNumber { get; set; }

        [EdiValue("X(2)", Path = "UNH/1/3")]
        public string ControllingAgency { get; set; }

        [EdiValue("X(6)", Path = "UNH/1/4")]
        public string AssociationAssignedCode { get; set; } //AssociationAssignedCode

        public Übertragungsdatei Übertragungsdatei { get; set; }

        public CONTRLEndMessage CONTRLEndMessage { get; set; }

        public override String ToString()
        {
            String header = $"UNH+{NachrichtKey}+{MessageType}:{Version}:{ReleaseNumber}:{ControllingAgency}:{AssociationAssignedCode}'";

            return header;
        }
    }

    #region Document

    [EdiSegment, EdiPath("UNB")]
    public class HeaderDocument
    {
        [EdiValue("X(4)", Mandatory = true, Path = "UNB/0")]
        public string SyntaxIdentifier { get; set; }

        [EdiValue("9(1)", Path = "UNB/0/1", Mandatory = true)]
        public int SyntaxVersion { get; set; }

        [EdiValue("X(35)", Path = "UNB/1/0", Mandatory = true)]
        public string SenderId { get; set; }

        [EdiValue("X(4)", Path = "UNB/1/1", Mandatory = true)]
        public string PartnerIDCodeQualifier { get; set; }

        [EdiValue("X(35)", Path = "UNB/2/0", Mandatory = true)]
        public string RecipientId { get; set; }

        [EdiValue("X(4)", Path = "UNB/2/1", Mandatory = true)]
        public string ParterIDCode { get; set; }

        [EdiValue("9(6)", Path = "UNB/3/0", Format = "yyMMdd", Description = "Date of Preparation")]
        [EdiValue("9(4)", Path = "UNB/3/1", Format = "HHmm", Description = "Time or Prep")]
        public DateTime DateOfPreparation { get; set; }

        [EdiValue("X(14)", Path = "UNB/4/0", Mandatory = true)]
        public String ControlRef { get; set; }

        public override String ToString()
        {
            String header = $"UNB+UNOC:{SyntaxVersion}+{SenderId}:{PartnerIDCodeQualifier}+{RecipientId}:{ParterIDCode}+{DateOfPreparation.ToString("yyMMdd")}:{DateOfPreparation.ToString("HHmm")}+{ControlRef}'";

            return header;
        }
    }

    [EdiElement, EdiPath("UNZ/0")]
    public class FootDocument
    {
        [EdiValue("9(1)", Path = "UNZ/0/0")]
        public String MessageNumber { get; set; }

        [EdiValue("X(14)", Path = "UNZ/1/0", Mandatory = true)]
        public String DocumentRef { get; set; }

        public override String ToString()
        {
            String header = $"UNZ+{MessageNumber}+{DocumentRef}'";

            return header;
        }
    }

    #endregion

    public class CONTRL
    {
        public HeaderDocument HeaderDocument { get; set; }

        public CONTRLMessage CONTRLMessage { get; set; }

        public FootDocument FootDocument { get; set; }
    }

    [EdiSegment, EdiPath("UNT")]
    public class CONTRLEndMessage
    {
        [EdiValue("X(6)", Path = "UNT/0/0")]
        public String SegmentCounter { get; set; }

        [EdiValue("X(14)", Path = "UNT/1")]
        public string NachrichtKey { get; set; }

        public override String ToString()
        {
            String header = $"UNT+{SegmentCounter}+{NachrichtKey}'";

            return header;
        }
    }

    [EdiSegment, EdiPath("UCI")]
    public class Übertragungsdatei
    {
        [EdiValue("X(14)", Path = "UCI/0/0")]
        public String Referenz { get; set; }

        [EdiValue("9(35)", Path = "UCI/1/0")]
        public String Receiver { get; set; }

        [EdiValue("X(4)", Path = "UCI/1/1")]
        public String ReceiverMPCode { get; set; }

        [EdiValue("9(35)", Path = "UCI/2/0")]
        public String Sender { get; set; }

        [EdiValue("9(35)", Path = "UCI/2/1")]
        public String SenderMPCode { get; set; }

        [EdiValue("9(1)", Path = "UCI/3/0")]
        public String Status { get; set; }

        [EdiValue("9(2)", Path = "UCI/4/0")]
        public String SyntaxFehler { get; set; }

        [EdiValue("X(3)", Path = "UCI/5/0")]

        public String ServiceSegment { get; set; }

        [EdiValue("X(3)", Path = "UCI/6/0")]

        public String Segmentposition { get; set; }

        [EdiValue("X(3)", Path = "UCI/6/1")]

        public String Gruppenposition { get; set; }

        public List<AntwortSegment> AntwortSegment { get; set; }

        public override String ToString()
        {
            String header = $"UCI+{Referenz}+{Receiver}:{ReceiverMPCode}+{Sender}:{SenderMPCode}+{Status}'";

            return header;
        }
    }

    [EdiSegment, EdiPath("UCM")]
    public class AntwortSegment
    {
        [EdiValue("X(14)", Path = "UCM / 0 / 0")]

        public String Referenz { get; set; }

        [EdiValue("X(6)", Path = "UCM/1/0")]
        public String NachrichtenTyp { get; set; }

        [EdiValue("X(1)", Path = "UCM/1/1")]
        public String NachrichtVersion { get; set; }

        [EdiValue("X(3)", Path = "UCM/1/2")]
        public String Freigabenummer { get; set; }

        [EdiValue("X(2)", Path = "UCM/1/3")]
        public String ControllingAgency { get; set; } //UN

        [EdiValue("X(2)", Path = "UCM/1/4")]
        public String Anwendungscode { get; set; }

        [EdiValue("X(1)", Path = "UCM/2/0")]
        public String Action { get; set; } //4

        [EdiValue("9(2)", Path = "UCM/3/0")]
        public String SyntaxFehler { get; set; }

        [EdiValue("X(3)", Path = "UCM/4/0")]

        public String ServiceSegment { get; set; }

        [EdiValue("X(3)", Path = "UCM/5/0")]

        public String Segmentposition { get; set; }

        [EdiValue("X(3)", Path = "UCM/5/1")]

        public String Gruppenposition { get; set; }


        public List<FehlerSegments> FehlerSegments { get; set; }
    }

    [EdiSegment, EdiPath("UCS")]
    public class FehlerSegments
    {
        [EdiValue("X(6)", Path = "UCS/0/0")]
        public String Segmentposition { get; set; }

        [EdiValue("9(2)", Path = "UCS/1/0")]

        public String Syntaxfehler { get; set; }

        public List<Fehlerelement> Fehlerelement { get; set; }
    }

    [EdiSegment, EdiPath("UCD")]
    public class Fehlerelement
    {
        [EdiValue("9(2)", Path = "UCD/0/0")]
        public String SyntaxFehler { get; set; }

        [EdiValue("X(3)", Path = "UCD/1/0")]

        public String Segmentposition { get; set; }

        [EdiValue("X(3)", Path = "UCD/1/1")]

        public String Gruppenposition { get; set; }

    }

It is working as expected for the UNB, UNH, UCI, and UNT, but not for the UNZ. It is missing the DocumentRef.

Any ideas? Wrong using of attributes? Is there any docu for the attributes usage?

Thanks so much.

Compression in EDIFACT messages

I believe the current serializer does not implement the EDIFACT specs on compression: https://web-beta.archive.org/web/20161004192113/www.unece.org/trade/untdid/texts/d422_d.htm#p7

The sample edifact.01.edn message contains the following line (here)
UNB+UNOC:3+1234567891123:14+7080005059275:14:SPOTMARKED+101012:1104+HBQ001++++1'

The unit test expected value has an extra ':' behind the 14, creating an ':+' combination (here)
UNB+UNOC:3+1234567891123:14:+7080005059275:14:SPOTMARKED+101012:1104+HBQ001++++1'

I believe the specs describe that the : should be omitted.

I will see if I can change this behavior and create an PR

Strip numeric 'Z' padding on Read

Consider stripping Z padding. This is another cobol thingy!?

Se generally when this "Z13" is found inside the value of a component and we know by the specs that this is a number with 3 digits, instead of padding it with zeros some numeric values are padded with Zs

Instead of 013
We get Z13

Deserialization (EDI to POCOs) - X12_214 not deserialize "Functional Group Trailer" GE

When deserializing using a EdiGrammar NewX12 with model on test example, values GE01 (Number of Transaction Sets Included) and GE02 (Group Control Number) have values 0, after deserialize.
I used exactly the files of the examples.

How to define a POCO to DESERIALIZE correctly these values?

Kind regards

EDI file example:

ISA*00*          *00*          *02*SCAC           *ZZ*MGCTLYST       
*160726*1303*U*00403*000082265*0*T*>~
GS*QM*SCAC*MGCTLYST*20160726*1303*82265*X*004030~
ST*214*822650001~
B10*1751807*75027674*SCAC~
N1*SH*CATALYST PAPER (USA) INC~
N3*DUMP ROAD~
N4*RUMFORD*ME*04276~
N1*CN*FIBERMARK, INC~
N3*161 WELLINGTON ROAD~
N4*BRATTLEBORO*VT*05301~
N1*BT*CATALYST PAPER~
N3*1 DUMP ROAD~
N4*RUMFORD*ME*04276~
LX*1~
AT7*D1*NS***20160726*1230*LT~
MS1*BRATTLEBORO*VT~
MS2*SCAC*30402~
SE*16*822650001~
GE*1*82265~
IEA*1*000082265~

POCO Model example:

            [EdiValue("X(2)", Path = "GS/6", Format = "HHmm", Description = "455 Responsible Agency Code")]
            public string AgencyCode { get; set; }

            [EdiValue("X(2)", Path = "GS/7", Format = "HHmm", Description = "480 Version / Release / Industry Identifier Code")]
            public string Version { get; set; }

            public List<Message> Messages { get; set; }

            [EdiValue("9(1)", Path = "GE/0", Description = "97 Number of Transaction Sets Included")]
            public int TransactionsCount { get; set; }

            [EdiValue("9(9)", Path = "GE/1", Description = "28 Group Control Number")]
            public int GroupTrailerControlNumber { get; set; }

Deserialization example:

var grammar = EdiGrammar.NewX12();
var interchange = default(Transportation_214);
using (var stream = new StreamReader(@"x12.214.edi"))
{
    interchange = new EdiSerializer().Deserialize<Transportation_214>(stream, grammar);
}

Interchange trailer in separate class

I have defined POCO Interchange and InterchangeTrailer in separate segment class

    public class Interchange
    {
        public Interchange()
        {
            this.InterchangeHeader = new InterchangeHeader();
            this.Quote = new Quote();
            this.InterchangeTrailer = new InterchangeTrailer();
        }

        public InterchangeHeader InterchangeHeader { get; set; }

        public Quote Quote { get; set; }

        public InterchangeTrailer InterchangeTrailer { get; set; }
    }
    [EdiSegment, EdiPath("UNZ")]
    public class InterchangeTrailer
    {
        [EdiValue("X(1)", Path = "UNZ/0")]
        public string TrailerControlCount { get; set; }

        [EdiValue("X(14)", Path = "UNZ/1")]
        public string TrailerControlReference { get; set; }
    }

If i try to deserialize edi file InterchangeTrailer is empty.
Similar problem with UNH - message header.
Serialization is ok.

Properties getting instanciated but with no data

Hi there, following the structure

-NAD
   -COM
       -CTA

2017-04-04_15-09-21

I have made:

[EdiSegmentGroup("NAD")]
public class NAD
{
    [EdiValue("X(3)", Path = "NAD/0/0")]
    public string Qualifier { get; set; }

    [EdiValue("X(35)", Path = "NAD/1/0")]
    public string ID { get; set; }

    [EdiValue("X(3)", Path = "NAD/1/2")]
    public string Code { get; set; }

    public CTA CTA { get; set; }
}

[EdiSegmentGroup("CTA")]
public class CTA
{
    [EdiValue("X(3)")]
    [EdiPath("CTA/0/0")]
    public string Funktion { get; set; }

    [EdiValue("X(17)")]
    [EdiPath("CTA/1/0")]
    public string Kontaktnummer { get; set; }

    [EdiValue("X(255)")]
    [EdiPath("CTA/1/1")]
    public string Kontakt { get; set; }

    //public List<COM> Com { get; set; }

    [EdiCondition("TE", Path = "COM/0/1")]
    public COM TE { get; set; }

    [EdiCondition("EM", Path = "COM/0/1")]
    public COM EM { get; set; }
}

[EdiSegment]
[EdiPath("COM")]
public class COM
{
    [EdiValue("X(255)")]
    [EdiPath("COM/0/0")]
    public string Kommunikationsverbindung { get; set; }

    [EdiValue("X(3)")]
    [EdiPath("COM/0/1")]
    public string Art { get; set; }
}

The CTA is instantiated (both, TE and EM) but with no date inside. If I use instead the //commented property List<COM> Com everything gets serialised there. I guess is a wrong using of attributes?

I also realised that you use Byte for the Picture, in this example the field COM/0/0, "Kommunikationsverbiundung" can be up to 512 characters, which causes an exception, guess is not important on that field, but there are some others where the user can input free text (for example, to explain why a specific message is rejected).
chrome_2017-04-10_12-06-34

I have made a pull request with the a cleaned ORDRSP class and the correct fixes for #36 including also a test for this scenario.
Hope you can help me. Thanks!

Path parse handles one Letter and two Digit Segment names like "B10"

In X12 it is quite common to have number suffixes in the name of the segment. Currently there seems to be a bug with the way we parse the paths provided on the EdiPathAttribute etc.

There is a RegEx that is handling the paths.
Currently N1 is recognized but B10 fails. Issue #15 mentions this.
Clearly a bug.

IDoc support would be aweasome

IDoc (SAP format) is based on EDI I think.

It would be great to have the possibility to parse IDoc's in a handy way.

Kind regards

Serializer

is this library still being worked on, and is there a time scale for the serializer part of this? our client has a requirement to send out EDI files in tradacoms format and this would save us a lot of time/effort

Syntax validator

I'm implementing a protocol that is very strict in validating the exchanged messages and requires extensive syntactic validation and detailed errors to be produced while serializing and validating the input.

At this point the Picture class only seems to be used to pick the correct formatting to read the elements and the provided length does not seem to trigger any validation errors at this point.

Ideally the serializer would take care of syntax validation and provide an exception with detailed information of all validation errors or an separate property that would indicate if the message is syntactically ok or a list of errors if not. The last option would be an non breaking change as you have to check the validation results and act on these yourself.

I'll be happy to implement this feature and create an pull request, but we need to specify exactly how this would fit into the current structure.

Add Support for Repeating multi-line Segements in EDI messages

Currently EDI.net has support for the concept of repeating segments which can be parsed into a strongly-typed collection type such as a List. This is supported by making a POCO with the EdiSegment attribute and then adding an EdiPath attribute to identify the segment in the file.

The proposal is to extend this feature to support a multi-line segment i.e. a segment that may span multiple lines in the file.

An example of this could be a time series which repeats n times. It is assumed that the repeating segment is sequentially repeating i.e. there are no other values , segments etc intermingled with the repeating segment.

The repeating segment will always have an identifier for the start of the segment and may or may not have a terminator. If there is no terminator then it is assumed the next instance of the identifier found in the file indicates that beginning of a new segment in the series.

example data : time series identified with "LIN" with no terminator, can repeat "n" times.

LIN+1++1420:::SM'
DTM+324:201010192300201010192400:Z13'
PRI+CAL:-2100'
RNG+4+Z01:-0.1'
PRI+CAL:21000'
RNG+4+Z01:-0.1'

LIN+2++1420:::SM'
DTM+324:201010200000201010200100:Z13'
PRI+CAL:-2100'
RNG+4+Z01:0'
PRI+CAL:21000'
RNG+4+Z01:0'

LIN+3++1420:::SM'
DTM+324:201010200100201010200200:Z13'
PRI+CAL:-2100'
RNG+4+Z01:0'
PRI+CAL:21000'
RNG+4+Z01:0'

LIN+4++1420:::SM'
DTM+324:201010200200201010200300:Z13'
PRI+CAL:-2100'RNG+4+Z01:0'
PRI+CAL:21000'
RNG+4+Z01:0'

Edi Reader does not respect X12 advised control characters

In all known EDI formats there are default control characters these are documented in the default EdiGrammar presets.

  • EdiGrammar.NewEdiFact()
  • EdiGrammar.NewX12()
  • EdiGrammar.NewTradacoms()

Now in the EdiFact and X12 cases there is a way for the transmitter (he who sends the edi transmission)
to advise differently for each of the control characters.

Control characters are considered to be the segment, element & component seperators plus the escape character.

In X12 the current implementation completely ignores them.

[Q] How to discriminate list of values.

Hi there,

In the format Edifact.ORDRSP there are several segments "IMD", which I cannot discriminate with EdiCondition as they have a list of possible values:
chrome_2017-03-29_12-26-23
chrome_2017-03-29_12-26-43
chrome_2017-03-29_12-26-07

Is there a way to specify more than one condition, or a list of possible values inside the EdiConditionAttribute so I can list all of them for each field? Or should I use instead EdiSegment and check the value to discriminate it programmatically so I know which field is?

Here the POCO (not completed) class:

using indice.Edi.Serialization;
using IQoneEDIParser.Formats;
using System;
using System.Collections.Generic;
using System.Xml.Serialization;

[XmlRoot("ORDRSP")]
[Serializable]
public class ORDRSP : ORDRSP
{
	private Syntax_Kennung _syntax_Kennung;

	private Absender _absender;

	private Empfänger _empfänger;

	private Dokumentdatum _dokumentdatum;

	private string _datenaustauschreferenz;

	private List<Nachricht> _listnachricht;

	[XmlElement("Syntax_Kennung", typeof(Syntax_Kennung))]
	public Syntax_Kennung Syntax_Kennung
	{
		get
		{
			return this._syntax_Kennung;
		}
		set
		{
			this._syntax_Kennung = value;
		}
	}

	[XmlElement("Absender", typeof(Absender))]
	public Absender Absender
	{
		get
		{
			return this._absender;
		}
		set
		{
			this._absender = value;
		}
	}

	[XmlElement("Empfänger", typeof(Empfänger))]
	public Empfänger Empfänger
	{
		get
		{
			return this._empfänger;
		}
		set
		{
			this._empfänger = value;
		}
	}

	[XmlElement("Dokumentdatum", typeof(Dokumentdatum))]
	public Dokumentdatum Dokumentdatum
	{
		get
		{
			return this._dokumentdatum;
		}
		set
		{
			this._dokumentdatum = value;
		}
	}

	[EdiValue("X(14)", "UNB/4"), XmlElement("Datenaustauschreferenz", typeof(string))]
	public string Datenaustauschreferenz
	{
		get
		{
			return this._datenaustauschreferenz;
		}
		set
		{
			this._datenaustauschreferenz = value;
		}
	}

	[XmlElement("Nachricht", typeof(Nachricht))]
	public List<Nachricht> ListNachricht
	{
		get
		{
			return this._listnachricht;
		}
		set
		{
			this._listnachricht = value;
		}
	}
}
[EdiElement, EdiPath("UNB[0][0]")]
[Serializable]
public class Syntax_Kennung
{
	private string _syntaxid;

	private int _sintaxversion;

	[EdiValue("X(4)", "UNB/0/0"), XmlElement("SyntaxID", typeof(string))]
	public string SyntaxID
	{
		get
		{
			return this._syntaxid;
		}
		set
		{
			this._syntaxid = value;
		}
	}

	[EdiValue("9(1)", "UNB/0/1"), XmlElement("Sintaxversion", typeof(int))]
	public int Sintaxversion
	{
		get
		{
			return this._sintaxversion;
		}
		set
		{
			this._sintaxversion = value;
		}
	}
}
[EdiElement, EdiPath("UNH[1][0]")]
[Serializable]
public class Nachrichten_Kennung
{
	private string _nachrichtentyp;

	private string _draftversion;

	private string _freigabenummer;

	private string _verwaltende_organisation;

	private string _versionsnummer;

	[EdiValue("X(6)", "UNH/1/0"), XmlElement("Nachrichtentyp", typeof(string))]
	public string Nachrichtentyp
	{
		get
		{
			return this._nachrichtentyp;
		}
		set
		{
			this._nachrichtentyp = value;
		}
	}

	[EdiValue("X(3)", "UNH/1/1"), XmlElement("DraftVersion", typeof(string))]
	public string DraftVersion
	{
		get
		{
			return this._draftversion;
		}
		set
		{
			this._draftversion = value;
		}
	}

	[EdiValue("X(3)", "UNH/1/2"), XmlElement("Freigabenummer", typeof(string))]
	public string Freigabenummer
	{
		get
		{
			return this._freigabenummer;
		}
		set
		{
			this._freigabenummer = value;
		}
	}

	[EdiValue("X(2)", "UNH/1/3"), XmlElement("Verwaltende_Organisation", typeof(string))]
	public string Verwaltende_Organisation
	{
		get
		{
			return this._verwaltende_organisation;
		}
		set
		{
			this._verwaltende_organisation = value;
		}
	}

	[EdiValue("X(6)", "UNH/1/4"), XmlElement("Versionsnummer", typeof(string))]
	public string Versionsnummer
	{
		get
		{
			return this._versionsnummer;
		}
		set
		{
			this._versionsnummer = value;
		}
	}
}
[EdiMessage]
[Serializable]
public class Nachricht
{
	private Nachrichten_Kennung _nachrichten_Kennung;

	private string _dokumentenname;

	private string _dokumentennummer;

	private DTM _nachrichtendatum;

	private DTM _ausführungsdatum;

	private DTM _verschobener_abmeldetermin;

	private List<IMD> _listimd;

	[XmlElement("Nachrichten_Kennung", typeof(Nachrichten_Kennung))]
	public Nachrichten_Kennung Nachrichten_Kennung
	{
		get
		{
			return this._nachrichten_Kennung;
		}
		set
		{
			this._nachrichten_Kennung = value;
		}
	}

	[EdiValue("X(3)", "BGM/0/0"), XmlElement("Dokumentenname", typeof(string))]
	public string Dokumentenname
	{
		get
		{
			return this._dokumentenname;
		}
		set
		{
			this._dokumentenname = value;
		}
	}

	[EdiValue("X(70)", "BGM/1/0"), XmlElement("Dokumentennummer", typeof(string))]
	public string Dokumentennummer
	{
		get
		{
			return this._dokumentennummer;
		}
		set
		{
			this._dokumentennummer = value;
		}
	}

	[EdiCondition("137", "DTM[0][0]"), XmlElement("Nachrichtendatum", null)]
	public DTM Nachrichtendatum
	{
		get
		{
			return this._nachrichtendatum;
		}
		set
		{
			this._nachrichtendatum = value;
		}
	}

	[EdiCondition("203", "DTM[0][0]"), XmlElement("Ausführungsdatum", null)]
	public DTM Ausführungsdatum
	{
		get
		{
			return this._ausführungsdatum;
		}
		set
		{
			this._ausführungsdatum = value;
		}
	}

	[EdiCondition("Z02", "DTM[0][0]"), XmlElement("Verschobener_Abmeldetermin", null)]
	public DTM Verschobener_Abmeldetermin
	{
		get
		{
			return this._verschobener_abmeldetermin;
		}
		set
		{
			this._verschobener_abmeldetermin = value;
		}
	}

	[XmlElement("IMD", typeof(IMD))]
	public List<IMD> ListIMD
	{
		get
		{
			return this._listimd;
		}
		set
		{
			this._listimd = value;
		}
	}
}
[EdiPath("IMD[0][0]"), EdiSegment]
[Serializable]
public class IMD
{
	private string _prodcode10;

	private string _prodcode20;

	[EdiValue("X(3)", "IMD/1/0"), XmlElement("ProdCode10", typeof(string))]
	public string ProdCode10
	{
		get
		{
			return this._prodcode10;
		}
		set
		{
			this._prodcode10 = value;
		}
	}

	[EdiValue("X(3)", "IMD/2/0"), XmlElement("ProdCode20", typeof(string))]
	public string ProdCode20
	{
		get
		{
			return this._prodcode20;
		}
		set
		{
			this._prodcode20 = value;
		}
	}
}
[EdiElement, EdiPath("UNB[2][0]")]
[Serializable]
public class Empfänger
{
	private string _id;

	private string _code_unb;

	[EdiValue("X(35)", "UNB/2/0"), XmlElement("ID", typeof(string))]
	public string ID
	{
		get
		{
			return this._id;
		}
		set
		{
			this._id = value;
		}
	}

	[EdiValue("X(4)", "UNB/2/1"), XmlElement("Code_UNB", typeof(string))]
	public string Code_UNB
	{
		get
		{
			return this._code_unb;
		}
		set
		{
			this._code_unb = value;
		}
	}
}
[EdiElement, EdiPath("DTM[0][0]")]
[Serializable]
public class DTM
{
	private string _code;

	private string _datum;

	private string _format;

	[EdiValue("X(3)", "DTM/0/0"), XmlElement("Code", typeof(string))]
	public string Code
	{
		get
		{
			return this._code;
		}
		set
		{
			this._code = value;
		}
	}

	[EdiValue("X(35)", "DTM/0/1"), XmlElement("Datum", typeof(string))]
	public string Datum
	{
		get
		{
			return this._datum;
		}
		set
		{
			this._datum = value;
		}
	}

	[EdiValue("X(3)", "DTM/0/2"), XmlElement("Format", typeof(string))]
	public string Format
	{
		get
		{
			return this._format;
		}
		set
		{
			this._format = value;
		}
	}
}
[EdiElement, EdiPath("UNB[3][0]")]
[Serializable]
public class Dokumentdatum
{
	private string _datum;

	private string _zeit;

	[EdiValue("X(6)", "UNB/3/0"), XmlElement("Datum", typeof(string))]
	public string Datum
	{
		get
		{
			return this._datum;
		}
		set
		{
			this._datum = value;
		}
	}

	[EdiValue("X(4)", "UNB/3/1"), XmlElement("Zeit", typeof(string))]
	public string Zeit
	{
		get
		{
			return this._zeit;
		}
		set
		{
			this._zeit = value;
		}
	}
}
[EdiElement, EdiPath("UNB[1][0]")]
[Serializable]
public class Absender
{
	private string _id;

	private string _code_unb;

	[EdiValue("X(35)", "UNB/1/0"), XmlElement("ID", typeof(string))]
	public string ID
	{
		get
		{
			return this._id;
		}
		set
		{
			this._id = value;
		}
	}

	[EdiValue("X(4)", "UNB/1/1"), XmlElement("Code_UNB", typeof(string))]
	public string Code_UNB
	{
		get
		{
			return this._code_unb;
		}
		set
		{
			this._code_unb = value;
		}
	}
}

Here a test message:

UNA:+.? 
UNB+UNOC:3+9900080000007:500+990000000000X:500+160321:1425+DAREFNR0000001
UNH+9IMX20YSP0009+ORDRSP:D:10A:UN:1.1e
BGM+Z12+IM20U000000000CNF
DTM+137:201603211421:203
DTM+203:20151023:102
DTM+Z02:20110408:102
IMD++Z01
IMD++Z10
IMD++Z14+Z07
RFF+ON:00001672
DTM+171:201510231149:203
RFF+Z13:19101
AJT+Z15
NAD+MS+9900080000007::293
CTA+IC+:Seipt, Thomas
COM+?+49 030 49202 8652:TE
[email protected]:EM
NAD+MR+990000000000X::293
NAD+DP
LOC+172+DE12345610243DE000000000000000026
CUX+2:EUR:9
LIN+1++9900010000649:Z01
QTY+145:1:PCS
MOA+203:825
FTX+ACB+++Text1:Text2:Text3:Text4:Text5
PRI+CAL:50.5
RFF+Z09:8465929523
RFF+Z06:7
UNS+S
MOA+24:9
UNT+17+9IM20YSP9
UNZ+1+DAREFNR00001

Hope you can help out, Thanks in advance!

Reading multiple reference from line item

Hi. I need help. I want to "enhance" your example (Edifact_ORDRSPTests) with parsing more details from example edi file edifact.ORDRSP. I would like to read references from line-items in this example:
RFF+Z09:8465929523'
RFF+Z06:7'

I have added class:

    [EdiSegment]
    [EdiPath("RFF")]
    public class MyRff
    {
        [EdiValue("X(70)", Path = "RFF/0/1")]
        public string Code { get; set; }

        [EdiValue("X(3)", Path = "RFF/0/0")]
        public string Qualifier { get; set; }
    }

and then inside LineItem class:

        [EdiCondition("Z09", Path = "RFF/0")]
        public MyRff ReferenceZ09 { get; set; }

        [EdiCondition("Z06", Path = "RFF/0")]
        public MyRff ReferenceZ06 { get; set; }`

But data is not parsed into LineItem class. What am I doing wrong?

Thanks for help.

Matej Golob

Support reusing the same Element class under different Segment context.

The issue here is that although Element to Class binding is supported there is currently no way to make declared paths relative. Thus the element to POCO class feature is almost useless.

For example if an element (group of components) for the address field occurs more than one in a Message type there could be one class to handle the deserialization. Now the class is bound to one and only segment occurrence because Paths are treated as absolute and are not combined & computed on deserialization

UNH and UNZ segments in separate classes

In my POCO structure I like to create the segments in separate classes because a lot of the messages share segments. This works fine for all segments except UNH and UNZ.

As you can see the UNH and UNZ segments are null:
image

The message itself is composed as follows:
image

This is the UNH segment class with the attributes applied:
image

This is the UNZ segment class with the attributes applied:
image

I have written an unit test to reproduce these cases.
I also have taken a look at the flow inside the EdiSerializer, DeserializeInternal method and I moved some parts around so that after handling of reader.IsStartMessage and reader.IsEndInterchange the flow also handles the creation of a new segment container.

I will start an pull request to submit the unit test and suggested flow changes.

Make unit tests work with dnx & xUnit

Should make unit test project work with xUnit. Currently I am relying to a console app to test this. Ideally make this work with the visual studio test window.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.