class EDI::E::Interchange
Interchange: Class of the top-level objects of UN/EDIFACT data
Attributes
Public Class Methods
Create an empty UN/EDIFACT interchange
Supported parameters (passed hash-style):¶ ↑
Essentials, should not be changed later¶ ↑
- :charset
-
Sets S001.0001, default = ‘UNOB’
- :version
-
Sets S001.0002, default = 3
- :i_edi
-
Interactive
EDI
mode, a boolean (UIB instead of UNB …), default = false
Optional parameters affecting to_s
, with corresponding setters¶ ↑
- :show_una
-
Adds
UNA
sement to output, default = true - :output_mode
-
See setter output_mode=(), default = :verbatim
- :una_string
-
See class
UNA
for setters, default = nil
Optional UNB presets for your convenience, may be changed later¶ ↑
- :sender
-
Presets
DE
S002/0004, default = nil - :recipient
-
Presets
DE
S003/0010, default = nil - :interchange_control_reference
-
Presets
DE
0020, default = ‘1’ - :application_reference
-
Presets
DE
0026, default = nil - :interchange_agreement_id
-
Presets
DE
0032, default = nil - :acknowledgment_request
-
Presets
DE
0031, default = nil - :test_indicator
-
Presets
DE
0035, default = nil
Notes¶ ↑
-
Date and time in S004 are set to the current values automatically.
-
Add or change any data element later, except those in S001.
Examples:¶ ↑
-
ic =
EDI::E::Interchange.new
# Empty interchange, default settings -
ic =
EDI::E::Interchange.new
(:charset=>‘UNOC’, :output_mode=>:linebreak)
EDI::Interchange::new
# File lib/edi4r/edifact.rb, line 372 def initialize( user_par={} ) super( user_par ) # just in case... if (illegal_keys = user_par.keys - @@interchange_default_keys) != [] msg = "Illegal parameter(s) found: #{illegal_keys.join(', ')}\n" msg += "Valid param keys (symbols): #{@@interchange_default_keys.join(', ')}" raise ArgumentError, msg end par = @@interchange_defaults.merge( user_par ) @messages_created = @groups_created = 0 @syntax = 'E' # par[:syntax] # E = UN/EDIFACT @e_iedi = par[:i_edi] @charset = par[:charset] @version = par[:version] @una = UNA.new(self, par[:una_string]) self.output_mode = par[:output_mode] self.show_una = par[:show_una] check_consistencies init_ndb( @version ) if @e_iedi # Interactive EDI raise "I-EDI not supported yet" # Fill in what we already know about I-EDI: @header = new_segment('UIB') @trailer = new_segment('UIZ') @header.cS001.d0001 = par[:charset] @header.cS001.d0002 = par[:version] @header.cS002.d0004 = par[:sender] unless par[:sender].nil? @header.cS003.d0010 = par[:recipient] unless par[:recipient].nil? @header.cS302.d0300 = par[:interchange_control_reference] # FIXME: More to do in S302... x= :test_indicator; @header.d0035 = par[x] unless par[x].nil? t = Time.now @header.cS300.d0338 = t.strftime(par[:version]==4 ? '%Y%m%d':'%y%m%d') @header.cS300.d0314 = t.strftime("%H%M") @trailer.d0036 = 0 ch, ct = @header.cS302, @trailer.cS302 ct.d0300, ct.d0303, ct.d0051, ct.d0304 = ch.d0300, ch.d0303, ch.d0051, ch.d0304 else # Batch EDI @header = new_segment('UNB') @trailer = new_segment('UNZ') @header.cS001.d0001 = par[:charset] @header.cS001.d0002 = par[:version] @header.cS002.d0004 = par[:sender] unless par[:sender].nil? @header.cS003.d0010 = par[:recipient] unless par[:recipient].nil? @header.d0020 = par[:interchange_control_reference] x= :application_reference; @header.d0026 = par[x] unless par[x].nil? x= :acknowledgment_request; @header.d0031 = par[x] unless par[x].nil? x= :interchange_agreement_id; @header.d0032 = par[x] unless par[x].nil? x= :test_indicator; @header.d0035 = par[x] unless par[x].nil? t = Time.now @header.cS004.d0017 = t.strftime(par[:version]==4 ? '%Y%m%d':'%y%m%d') @header.cS004.d0019 = t.strftime("%H%M") @trailer.d0036 = 0 end end
Reads EDIFACT data from given stream (default: $stdin), parses it and returns an Interchange
object
# File lib/edi4r/edifact.rb, line 447 def Interchange.parse( hnd=$stdin, auto_validate=true ) builder = StreamingBuilder.new( auto_validate ) builder.go( hnd ) builder.interchange end
Returns a REXML document that represents the interchange
- xdoc
-
REXML document that contains the XML representation of a UN/EDIFACT interchange
# File lib/edi4r/edifact-rexml.rb, line 34 def Interchange.parse_xml( xdoc ) _root = xdoc.root _header = _root.elements["Header"] _trailer = _root.elements["Trailer"] _una = _header.elements["Parameter[@name='UNA']"] _una = _una.text.strip if _una raise "Empty UNA" if _una and _una.empty? # remove later! # S001: Works for both batch and interactive EDI: _s001 = _header.elements["Segment/CDE[@name='S001']"] _version = _s001.elements["DE[@name='0002']"].text.to_i _charset = _s001.elements["DE[@name='0001']"].text.strip params = { :charset => _charset, :version => _version } if _una params[:una_string] = _una params[:show_una] = true end ic = Interchange.new( params ) if _root.elements["Message"].nil? # correct ?? _root.elements.each('MsgGroup') do |xel| ic.add( MsgGroup.parse_xml( ic, xel ), false ) end else _root.elements.each('Message') do |xel| ic.add( Message.parse_xml( ic, xel ), false ) end end ic.header = Segment.parse_xml( ic, _header.elements["Segment"] ) ic.trailer = Segment.parse_xml( ic, _trailer.elements["Segment"] ) ic.validate ic end
Read maxlen
bytes from $stdin (default) or from given stream (UN/EDIFACT data expected), and peek into first segment (UNB/UIB).
Returns an empty Interchange
object with a properly header filled.
Intended use:
Efficient routing by reading just UNB data: sender/recipient/ref/test
# File lib/edi4r/edifact.rb, line 462 def Interchange.peek(hnd=$stdin, params={}) # Handle to input stream builder = StreamingBuilder.new( false ) if params[:deep_peek] def builder.on_segment( s, tag ) end else def builder.on_ung( s ) throw :done end def builder.on_unh_uih( s, tag ) throw :done # FIXME: UNZ?? end end builder.go( hnd ) builder.interchange end
Read maxlen
bytes from $stdin (default) or from given stream (UN/EDIFACT data expected), and peek into first segment (UNB/UIB).
Returns an empty Interchange
object with a properly header filled.
Intended use:
Efficient routing by reading just UNB data: sender/recipient/ref/test
# File lib/edi4r/edifact-rexml.rb, line 76 def Interchange.peek_xml(xdoc) # Handle to REXML document _root = xdoc.root _header = _root.elements["Header"] _trailer = _root.elements["Trailer"] _una = _header.elements["Parameter[@name='UNA']"] _una = _una.text if _una raise "Empty UNA" if _una and _una.empty? # remove later! # S001: Works for both batch and interactive EDI: _s001 = _header.elements["Segment/CDE[@name='S001']"] _version = _s001.elements["DE[@name='0002']"].text.to_i _charset = _s001.elements["DE[@name='0001']"].text.strip params = { :charset => _charset, :version => _version } if _una params[:una_string] = _una params[:show_una] = true end ic = Interchange.new( params ) ic.header = Segment.parse_xml( ic, _header.elements["Segment"] ) ic.trailer = Segment.parse_xml( ic, _trailer.elements["Segment"] ) ic end
Public Instance Methods
Add either a MsgGroup
or Message
object to the interchange. Note: Don’t mix both types!
UNZ/UIZ counter DE
0036 is automatically incremented.
EDI::Interchange#add
# File lib/edi4r/edifact.rb, line 521 def add( obj, auto_validate=true ) super @trailer.d0036 += 1 #if @trailer # @trailer doesn't exist yet when parsing # FIXME: Warn/fail if UNH/UIH/UNG id is not unique (at validation?) end
Yields a readable, properly indented list of all contained objects, including the empty ones. This may be a very long string!
EDI::Collection#inspect
# File lib/edi4r/edifact.rb, line 590 def inspect( indent='', symlist=[] ) symlist << :una super end
Returns true
if this is an I-EDI interchange (Interactive EDI
)
# File lib/edi4r/edifact.rb, line 483 def is_iedi? @e_iedi end
Derive an empty message from this interchange context. Parameters may be passed hash-like. See Message.new
for details
# File lib/edi4r/edifact.rb, line 539 def new_message(params={}) @messages_created += 1 Message.new(self, params) end
Derive an empty message group from this interchange context. Parameters may be passed hash-like. See MsgGroup.new
for details
# File lib/edi4r/edifact.rb, line 531 def new_msggroup(params={}) # to be completed ... @groups_created += 1 MsgGroup.new(self, params) end
This method modifies the behaviour of method to_s
(): UN/EDIFACT interchanges and their components are turned into strings either “verbatim” (default) or in some more readable way. This method corresponds to a parameter with same name at creation time.
Valid values:
- :linebreak
-
One-segment-per-line representation
- :indented
-
Like :linebreak but with additional indentation (2 blanks per hierarchy level).
- :verbatim
-
No linebreak (default), ISO compliant
# File lib/edi4r/edifact.rb, line 499 def output_mode=( value ) super( value ) @e_linebreak = @e_indent = '' case value when :verbatim # NOP (default) when :linebreak @e_linebreak = "\n" when :indented @e_linebreak = "\n" @e_indent = ' ' else raise "Unknown output mode '#{value}'. Supported modes: :linebreak, :indented, :verbatim (default)" end end
Returns a REXML document that represents the interchange according to DIN 16557-4
EDI::Collection_HT#to_din16557_4
# File lib/edi4r/edifact-rexml.rb, line 122 def to_din16557_4( xdoc = REXML::Document.new ) externalID = "SYSTEM \"edifact.dtd\"" doc_element_name = 'EDIFACTINTERCHANGE' xdoc << REXML::XMLDecl.new xdoc << REXML::DocType.new( doc_element_name, externalID ) doc_el = REXML::Element.new( doc_element_name ) xel = REXML::Element.new( 'UNA' ) xel.attributes["UNA1"] = una.ce_sep.chr xel.attributes["UNA2"] = una.de_sep.chr xel.attributes["UNA3"] = una.decimal_sign.chr xel.attributes["UNA4"] = una.esc_char.chr xel.attributes["UNA5"] = una.rep_sep.chr xel.attributes["UNA6"] = una.seg_term.chr xdoc.elements << doc_el doc_el.elements << xel super( xdoc.root ) xdoc end
Returns the string representation of the interchange.
Type conversion and escaping are provided. The UNA
object is shown when show_una
is set to true
. See output_mode
for modifiers.
EDI::Collection_HT#to_s
# File lib/edi4r/edifact.rb, line 580 def to_s s = show_una ? una.to_s + @e_linebreak : '' postfix = '' << una.seg_term << @e_linebreak s << super( postfix ) end
Returns a REXML document that represents the interchange
EDI::Interchange#to_xml
# File lib/edi4r/edifact-rexml.rb, line 104 def to_xml( xdoc = REXML::Document.new ) rc = super # Add parameter(s) to header in rc[1] unless @una.nil? #@una.empty? xel = REXML::Element.new('Parameter') rc[1] << xel xel.attributes["name"] = 'UNA' xel.text = @una.to_s end # rc xdoc end
Returns the number of warnings found, writes warnings to STDERR
EDI::Collection_HT#validate
# File lib/edi4r/edifact.rb, line 598 def validate( err_count=0 ) if (h=self.size) != (t=@trailer.d0036) warn "Counter UNZ/UIZ, DE0036 does not match content: #{t} vs. #{h}" err_count += 1 end if (h=@header.cS001.d0001) != @charset warn "Charset UNZ/UIZ, S001/0001 mismatch: #{h} vs. #@charset" err_count += 1 end if (h=@header.cS001.d0002) != @version warn "Syntax version UNZ/UIZ, S001/0002 mismatch: #{h} vs. #@version" err_count += 1 end check_consistencies if is_iedi? if (t=@trailer.cS302.d0300) != (h=@header.cS302.d0300) warn "UIB/UIZ mismatch in initiator ref (S302/0300): #{h} vs. #{t}" err_count += 1 end # FIXME: Add more I-EDI checks else if (t=@trailer.d0020) != (h=@header.d0020) warn "UNB/UNZ mismatch in refno (DE0020): #{h} vs. #{t}" err_count += 1 end end # FIXME: Check if messages/groups are uniquely numbered super end
Private Instance Methods
Private method: Check if basic UNB elements are set properly
# File lib/edi4r/edifact.rb, line 646 def check_consistencies # FIXME - @syntax should be completely avoided, use sub-module name if not ['E'].include?(@syntax) # More anticipated here raise "#{@syntax} - syntax not supported!" end case @version when 1 if @charset != 'UNOA' raise "Syntax version 1 permits only charset UNOA!" end when 2 if not @charset =~ /UNO[AB]/ raise "Syntax version 2 permits only charsets UNOA, UNOB!" end when 3 if not @charset =~ /UNO[A-F]/ raise "Syntax version 3 permits only charsets UNOA...UNOF!" end when 4 # A,B: ISO 646 subsets, C-K: ISO-8859-x, X: ISO 2022, Y: ISO 10646-1 if not @charset =~ /UNO[A-KXY]/ raise "Syntax version 4 permits only charsets UNOA...UNOZ!" end else raise "#{@version} - no such syntax version!" end if @e_iedi and @version != 4 raise "Inconsistent parameters - I-EDI requires syntax version 4!" end @illegal_charset_pattern = Illegal_Charset_Patterns['@version'] # Add more rules ... end
Private method: Loads EDIFACT norm database
# File lib/edi4r/edifact.rb, line 636 def init_ndb(d0002, d0076 = nil) @basedata = EDI::Dir::Directory.create(root.syntax, :d0002 => @version, :d0076 => d0076, :is_iedi => is_iedi?) end