-*- mode: org -*-
#+TITLE:       sisu json
#+DESCRIPTION: documents - structuring, various output representations & search
#+FILETAGS:    :sisu:json:
#+AUTHOR:      Ralph Amissah
#+EMAIL:       [[mailto:ralph.amissah@gmail.com][ralph.amissah@gmail.com]]
#+COPYRIGHT:   Copyright (C) 2015 - 2021 Ralph Amissah
#+LANGUAGE:    en
#+STARTUP:     content hideblocks hidestars noindent entitiespretty
#+OPTIONS:     H:3 num:nil toc:t \n:nil @:t ::t |:t ^:nil _:nil -:t f:t *:t <:t
#+PROPERTY:    header-args  :exports code
#+PROPERTY:    header-args+ :noweb yes
#+PROPERTY:    header-args+ :eval no
#+PROPERTY:    header-args+ :results no
#+PROPERTY:    header-args+ :cache no
#+PROPERTY:    header-args+ :padline no
#+PROPERTY:    header-args+ :mkdirp yes
* json.rb
#+BEGIN_SRC ruby  :tangle "../lib/sisu/json.rb"
# <>
module SiSU_JSON
  require_relative 'se_hub_particulars'                 # se_hub_particulars.rb
    include SiSU_Particulars
  require_relative 'se'                                 # se.rb
    include SiSU_Env
  require_relative 'json_shared'                        # json_shared.rb
    include SiSU_JSON_Munge
  require_relative 'json_format'                        # json_format.rb
    include SiSU_JSON_Format
  require_relative 'json_persist'                       # json_persist.rb
  require_relative 'shared_metadata'                    # shared_metadata.rb
  @@alt_id_count=0
  @@tablefoot=''
  class Source
    def initialize(opt)
      @opt=opt
      @particulars=SiSU_Particulars::CombinedSingleton.instance.get_all(opt)
    end
    def read
      begin
        @env,@md,@ao_array=@particulars.env,@particulars.md,@particulars.ao_array
        unless @opt.act[:quiet][:set]==:on
          tool=if (@opt.act[:verbose_plus][:set]==:on \
          || @opt.act[:maintenance][:set]==:on)
            @env.program.web_browser +
            ' file://' +
            @md.file.output_path.json.dir + '/' +
            @md.file.base_filename.json
          elsif @opt.act[:verbose][:set]==:on
            @env.program.web_browser +
            ' file://' +
            @md.file.output_path.json.dir + '/' +
            @md.file.base_filename.json
          else "[#{@opt.f_pth[:lng_is]}] #{@opt.fno}"
          end
          (@opt.act[:verbose][:set]==:on \
          || @opt.act[:verbose_plus][:set]==:on \
          || @opt.act[:maintenance][:set]==:on) \
          ? SiSU_Screen::Ansi.new(
              @opt.act[:color_state][:set],
              'JSON',
              tool
            ).green_hi_blue
          : SiSU_Screen::Ansi.new(
              @opt.act[:color_state][:set],
              'JSON',
              tool
            ).green_title_hi
          if (@opt.act[:verbose_plus][:set]==:on \
          || @opt.act[:maintenance][:set]==:on)
            SiSU_Screen::Ansi.new(
              @opt.act[:color_state][:set],
              @opt.fns,
                '/' + @md.file.output_path.json.dir +
                '/' + @md.file.base_filename.json
            ).flow
          end
        end
        SiSU_JSON::Source::Songsheet.new(@particulars).song
      rescue
        SiSU_Errors::Rescued.new($!,$@,@opt.selections.str,@opt.fns).location do
          __LINE__.to_s + ':' + __FILE__
        end
      ensure
        SiSU_Env::CreateSite.new(@opt).cp_css
        Dir.chdir(@opt.f_pth[:pth])
      end
    end
    private
    class Songsheet
      def initialize(particulars)
        @env,@md,@ao_array,@particulars=
          particulars.env,particulars.md,particulars.ao_array,particulars
        @file=SiSU_Env::FileOp.new(@md)
      end
      def song
        begin
          SiSU_JSON::Source::Scroll.new(@particulars).songsheet
        rescue
          SiSU_Errors::Rescued.new($!,$@,@md.opt.selections.str,@md.fns).location do
            __LINE__.to_s + ':' + __FILE__
          end
        ensure
        end
      end
    end
    class Scroll
      require_relative 'json_shared'                   # json_shared.rb #check already called
      require_relative 'txt_shared'                     # txt_shared.rb
        include SiSU_TextUtils
      require_relative 'css'                            # css.rb
      def initialize(particulars)
        @env,@md,@ao_array=particulars.env,particulars.md,particulars.ao_array
        @tab="\t"
        @trans=SiSU_JSON_Munge::Trans.new(@md)
        @sys=SiSU_Env::SystemCall.new
        @per=SiSU_JSON_Persist::Persist.new
      end
      def songsheet
        begin
          pre
          @data=markup(@ao_array)
          post
          publish
        ensure
          SiSU_JSON_Persist::Persist.new.persist_init
        end
      end
    protected
      def embedded_endnotes(dob='')
        dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}(\d+)\s+(.+?)#{Mx[:en_a_c]}/,
            '\1 \2   ').
          gsub(/#{Mx[:en_b_o]}([*+]\d+)\s+(.+?)#{Mx[:en_b_c]}/,
            '\1 \2   ').
          gsub(/#{Mx[:en_a_o]}([*+]+)\s+(.+?)#{Mx[:en_a_c]}/,
            '\1 \2   ')
      end
      def extract_endnotes(dob='')
        notes=dob.obj.scan(/(?:#{Mx[:en_a_o]}|#{Mx[:en_b_o]})([\d*+]+\s+.+?)(?:#{Mx[:en_a_c]}|#{Mx[:en_b_c]})/)
        notes.flatten.each do |e|
          s=e.to_s
          util=SiSU_JSONutils::Clean.new(s)
          wrap=util.line_json_clean
          wrap=wrap.gsub(/^(\d+)\s+(.+?)\s*\Z/m, <<-WOK
\\n[\\1.] \\2
              WOK
            ).
            gsub(/^([*+]\d+)\s+(.+?)\s*\Z/m, <<-WOK
\\n[\\1.] \\2
              WOK
            ).
            gsub(/^([*+]+)\s+(.+?)\s*\Z/m, <<-WOK
\\n[\\1.] \\2
              WOK
            ).strip
#KEEP alternative presentation of endnotes
#        wrap=wrap.gsub(/^(\d+)\s+(.+?)\s*\Z/m, <
##{Ax[:tab]*2}\\1. \\2
##{Ax[:tab]*1}  
#WOK
#)
          @endnotes << wrap
        end
      end
      def json_head
        #metadata=SiSU_Metadata::Summary.new(@md).json.metadata
        #@per.head << metadata
      end
      def name_tags(dob)
        tags=''
        if defined? dob.tags \
        and dob.tags.length > 0 # insert tags "hypertargets"
          dob.tags.each do |t|
            tags=tags << %{ }
          end
        end
        tags
      end
      def json_structure(dob,attrib=nil)
        if dob.is ==:para \
        || dob.is ==:heading
          if dob.is==:heading
            lv=dob.ln
            dob.ln + 2
          else lv=nil
          end
          extract_endnotes(dob)
          dob.obj=dob.obj.
            gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'\1 '). #footnote/endnote clean
            gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'\1 ')
          util=SiSU_JSONutils::Clean.new(dob.obj)
          wrapped=util.line_json_clean
          @per.body << Ax[:tab]*1 + '{'
          if defined? dob.ocn and dob.ocn
            @per.body << Ax[:tab]*2 + '"ocn": ' + dob.ocn.to_s + '",'
          end
          if lv                                                                 # main text, contents, body KEEP
            @per.body <<
              Ax[:tab]*2 + %{"object": "} + wrapped + %{ } +
              ((@endnotes.length > 0) ? '",' : '"')
          else
            @per.body <<
              Ax[:tab]*2 + '"object": "' + wrapped +
              ((@endnotes.length > 0) ? '",' : '"')
          end
          if @endnotes.length > 0                                               # main text, endnotes KEEP
            @per.body <<
              Ax[:tab]*2 + '"endnotes": "' +
              @endnotes.compact.join.strip + '"'
          end
          @per.body << Ax[:tab]*1 + '},' # unless is last object then '}'
          @endnotes=[]
        end
      end
      def block_structure(dob)
        dob=@trans.markup_block(dob)
        dob.obj=dob.obj.strip.
          gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'\1 '). #footnote/endnote clean
          gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'\1 ') #footnote/endnote clean
        @per.body << Ax[:tab]*1 + '{'
        if defined? dob.ocn and dob.ocn
          @per.body << Ax[:tab]*2 + '"ocn": ' + dob.ocn.to_s + '",'
        end
        @per.body <<
          Ax[:tab]*2 + '"object": "' + dob.obj + '"'
          #((@endnotes.length > 0) ? '",' : '"')
        @per.body << Ax[:tab]*1 + '},' # unless is last object then '}'
      end
      def group_structure(dob)
        dob=@trans.markup_group(dob)
        dob.obj=dob.obj.strip.
          gsub(/#{Mx[:en_a_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_a_c]}/,'\1 '). #footnote/endnote clean
          gsub(/#{Mx[:en_b_o]}([\d*+]+)\s+(?:.+?)#{Mx[:en_b_c]}/,'\1 ') #footnote/endnote clean
        @per.body << Ax[:tab]*1 + '{'
        if defined? dob.ocn and dob.ocn
          @per.body << Ax[:tab]*2 + '"ocn": ' + dob.ocn.to_s + '",'
        end
        @per.body <<
          Ax[:tab]*2 + '"object": "' + dob.obj + '"'
          #((@endnotes.length > 0) ? '",' : '"')
        @per.body << Ax[:tab]*1 + '},' # unless is last object then '}'
      end
      def poem_structure(dob)
        dob=@trans.markup_group(dob)
        dob.obj=dob.obj.strip
        @per.body << Ax[:tab]*1 + '{'
        if defined? dob.ocn and dob.ocn
          @per.body << Ax[:tab]*2 + '"ocn": ' + dob.ocn.to_s + '",'
        end
        @per.body <<
          Ax[:tab]*2 + '"object": "' + dob.obj + '"'
          #((@endnotes.length > 0) ? '",' : '"')
        @per.body << Ax[:tab]*1 + '},' # unless is last object then '}'
      end
      def code_structure(dob)
        dob=@trans.markup_group(dob)
        dob.obj=dob.obj.gsub(/\s\s/,'  ').strip
        @per.body << Ax[:tab]*1 + '{'
        if defined? dob.ocn and dob.ocn
          @per.body << Ax[:tab]*2 + '"ocn": ' + dob.ocn.to_s + '",'
        end
        @per.body <<
          Ax[:tab]*2 + '"object": "' + dob.obj + '"'
          #((@endnotes.length > 0) ? '",' : '"')
        @per.body << Ax[:tab]*1 + '},' # unless is last object then '}'
      end
      def table_structure(dob)
        table=SiSU_JSON_Shared::TableJSON.new(dob)
        @per.body << Ax[:tab]*1 + '{'
        if defined? dob.ocn and dob.ocn
          @per.body << Ax[:tab]*2 + '"ocn": ' + dob.ocn.to_s + '",'
        end
        @per.body <<
          Ax[:tab]*2 + '"object": "' + table.table.obj + '"'
        #((@endnotes.length > 0) ? '",' : '"')
        @per.body << Ax[:tab]*1 + '},' # unless is last object then '}'
      end
      def markup(data)
        @endnotes=[]
        @rcdc=false
        @level,@cont,@copen,@json_contents_close=[],[],[],[]
        json_head
        (0..7).each { |x| @cont[x]=@level[x]=false }
        (4..7).each { |x| @json_contents_close[x]='' }
        data.each_with_index do |dob,i|
          dob=@trans.char_enc.utf8(dob) if @sys.locale =~/utf-?8/i #% utf8
          dob=@trans.markup(dob)
          if @rcdc==false \
          and (dob.obj =~/~meta/ \
          and dob.obj =~/Document Information/)
            @rcdc=true
          end
          if dob.obj !~/(^#{Rx[:meta]}|#{Mx[:br_eof]}|#{Mx[:br_endnotes]})/
            if not @rcdc
              x=SiSU_JSON_Format::FormatTextObject.new(@md,dob)
              if dob.is==:heading
                json_structure(dob)
                dob.obj=case dob.ln
                when 0 then x.heading_body0
                when 1 then x.heading_body1
                when 2 then x.heading_body2
                when 3 then x.heading_body3
                when 4 then x.heading_body4
                when 5 then x.heading_body5
                when 6 then x.heading_body6
                when 7 then x.heading_body7
                end
              else
                if dob.is ==:verse
                  poem_structure(dob)
                elsif dob.is ==:group
                  group_structure(dob)
                elsif dob.is ==:block
                  block_structure(dob)
                elsif dob.is ==:code
                  code_structure(dob)
                elsif dob.is ==:table
                  table_structure(dob)
                elsif dob.is ==:para \
                and dob.indent.to_s =~/[1-9]/ \
                and dob.bullet_==true
                  json_structure(dob,"indent_bullet#{dob.indent}")
                elsif dob.is ==:para \
                and dob.indent.to_s =~/[1-9]/ \
                and dob.indent == dob.hang
                  json_structure(dob,"indent#{dob.indent}")
                elsif dob.is==:para \
                and dob.hang.to_s =~/[0-9]/ \
                and dob.indent != dob.hang
                  json_structure(dob,"hang#{dob.hang.to_s}_indent#{dob.indent.to_s}")
                else json_structure(dob)
                end
              end
            end
            dob.obj=dob.obj.gsub(/#{Mx[:pa_o]}:\S+#{Mx[:pa_c]}/,'') if dob.obj
          end
        end
        6.downto(4) do |x|
          y=x - 1; v=x - 3
          @per.body << "#{Ax[:tab]*5}\n#{Ax[:tab]*y}" if @level[x]==true
        end
        3.downto(1) do |x|
          y=x - 1
          @per.body << "#{Ax[:tab]*y}" if @level[x]==true
        end
      end
      def pre
        @per.head,@per.body=[],[]
        @per.open = '{'
      end
      def post
        @per.close = '}'
      end
      def publish
        content=[]
        @per.body[-1] = @per.body[-1].gsub(/,$/, '') #= Ax[:tab]*1 + '}'
        content << @per.open << @per.head << @per.body << @per.metadata
        content << @per.tail << @per.close
        content=content.flatten.compact
        Output.new(content,@md).json
      end
    end
    class Output
      def initialize(data,md)
        @data,@md=data,md
        @file=SiSU_Env::FileOp.new(@md)
      end
      def json
        SiSU_Env::FileOp.new(@md).mkdir
        filename_json=@file.write_file.json
        @data.each do |str|
          str=str.gsub(/\A\s+\Z/m,'') #str.gsub(/^\s+$/,'')
          filename_json.puts str unless str.empty?
        end
        filename_json.close
      end
    end
  end
end
__END__
#+END_SRC
* json_parts.rb
#+BEGIN_SRC ruby  :tangle "../lib/sisu/json_parts.rb"
# <>
module SiSU_Parts_JSON
  require_relative 'generic_parts'                       # generic_parts.rb
  include SiSU_Parts_Generic
  def the_line_break
    ' '
  end
  def the_table_close
    '
'
  end
  def the_url_decoration
    def xml_open                     #'<'
      Dx[:url_o]
    end
    def xml_close                    #'>'
      Dx[:url_c]
    end
    def txt_open
      '['
    end
    def txt_close
      ']'
    end
    self
  end
end
module SiSU_Proj_XML
  require_relative 'html_parts'                         # html_parts.rb
  require_relative 'se'                                 # se.rb
  include SiSU_Env
  class Bits < SiSU_Proj_HTML::Bits
  end
end
__END__
#+END_SRC
* json_shared.rb
#+BEGIN_SRC ruby  :tangle "../lib/sisu/json_shared.rb"
# <>
module SiSU_JSONutils
  require_relative 'generic_parts'                      # generic_parts.rb
  class Clean
    def initialize(para='')
      @para=para
      #@para,@n_char_max,@n_indent,@post,=para,n_char_max,n_indent,post
      #@n_char_max_extend = n_char_max
      #@n_hang=n_hang ? n_hang : @n_indent
    end
    def line_json_clean
      @para=@para.gsub(/ /,' \\ ').
        gsub(/#{Mx[:br_nl]}/,"\n\n").
        gsub(/"/,'\"').
        gsub(/'/,"\\\\'")
      @para
    end
  end
end
module SiSU_JSON_Munge
  require_relative 'json_parts'                         # json_parts.rb
  class Trans
    include SiSU_Parts_JSON
    def initialize(md)
      @md=md
      @sys=SiSU_Env::SystemCall.new
      @dir=SiSU_Env::InfoEnv.new(@md.fns)
      if @md.sem_tag
        @ab ||=semantic_tags.default
      end
    end
    def semantic_tags
      def default
        {
          pub:   'publication',
          conv:  'convention',
          vol:   'volume',
          pg:    'page',
          cty:   'city',
          org:   'organization',
          uni:   'university',
          dept:  'department',
          fac:   'faculty',
          inst:  'institute',
          co:    'company',
          com:   'company',
          conv:  'convention',
          dt:    'date',
          y:     'year',
          m:     'month',
          d:     'day',
          ti:    'title',
          au:    'author',
          ed:    'editor', #editor?
          v:     'version', #edition
          n:     'name',
          fn:    'firstname',
          mn:    'middlename',
          ln:    'lastname',
          in:    'initials',
          qt:    'quote',
          ct:    'cite',
          ref:   'reference',
          ab:    'abreviation',
          def:   'define',
          desc:  'description',
          trans: 'translate',
        }
      end
      self
    end
    def char_enc #character encode
      def utf8(dob='')
        if @sys.locale =~/utf-?8/i # instead ucs for utf8 # String#encode Iñtërnâtiônàlizætiøn
          str=if defined? dob.obj then dob.obj
          elsif dob.is_a?(String) then dob
          end
          if str
            #¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûü
            #¢£¥§©ª«®°±²³µ¶¹º»¼½¾×÷
            str=str.gsub(//um,'>').    # '>'     # >
              gsub(/¢/um,'¢').   # '¢'   # ¢
              gsub(/£/um,'£').   # '£'  # £
              gsub(/¥/um,'¥').   # '¥'    # ¥
              gsub(/§/um,'§').   # '§'   # §
              gsub(/©/um,'©').   # '©'   # ©
              gsub(/ª/um,'ª').   # 'ª'   # ª
              gsub(/«/um,'«').   # '«'  # «
              gsub(/®/um,'®').   # '®'    # ®
              gsub(/°/um,'°').   # '°'    # °
              gsub(/±/um,'±').   # '±' # ±
              gsub(/²/um,'²').   # '²'   # ²
              gsub(/³/um,'³').   # '³'   # ³
              gsub(/µ/um,'µ').   # 'µ'  # µ
              gsub(/¶/um,'¶').   # '¶'   # ¶
              gsub(/¹/um,'¹').   # '¹'   # ¹
              gsub(/º/um,'º').   # 'º'   # º
              gsub(/»/um,'»').   # '»'  # »
              gsub(/¼/um,'¼').   # '¼' # ¼
              gsub(/½/um,'½').   # '½' # ½
              gsub(/¾/um,'¾').   # '¾' # ¾
              gsub(/×/um,'×').   # '×'  # ×
              gsub(/÷/um,'÷').   # '÷' # ÷
              gsub(/¿/um,'¿').   # '¿' # ¿
              gsub(/À/um,'À').   # 'À' # À
              gsub(/Á/um,'Á').   # 'Á' # Á
              gsub(/Â/um,'Â').   # 'Â'  # Â
              gsub(/Ã/um,'Ã').   # 'Ã' # Ã
              gsub(/Ä/um,'Ä').   # 'Ä'   # Ä
              gsub(/Å/um,'Å').   # 'Å'  # Å
              gsub(/Æ/um,'Æ').   # 'Æ'  # Æ
              gsub(/Ç/um,'Ç').   # 'Ç' # Ç
              gsub(/È/um,'È').   # 'È' # È
              gsub(/É/um,'É').   # 'É' # É
              gsub(/Ê/um,'Ê').   # 'Ê'  # Ê
              gsub(/Ë/um,'Ë').   # 'Ë'   # Ë
              gsub(/Ì/um,'Ì').   # 'Ì' # Ì
              gsub(/Í/um,'Í').   # 'Í' # Í
              gsub(/Î/um,'Î').   # 'Î'  # Î
              gsub(/Ï/um,'Ï').   # 'Ï'   # Ï
              gsub(/Ð/um,'Ð').   # 'Ð'    # Ð
              gsub(/Ñ/um,'Ñ').   # 'Ñ' # Ñ
              gsub(/Ò/um,'Ò').   # 'Ò' # Ò
              gsub(/Ó/um,'Ó').   # 'Ó' # Ó
              gsub(/Ô/um,'Ô').   # 'Ô'  # Ô
              gsub(/Õ/um,'Õ').   # 'Õ' # Õ
              gsub(/Ö/um,'Ö').   # 'Ö'   # Ö
              gsub(/Ø/um,'Ø').   # 'Ø' # Ø
              gsub(/Ù/um,'Ù').   # 'Ù' # Ù
              gsub(/Ú/um,'Ú').   # 'Ú' # Ú
              gsub(/Û/um,'Û').   # 'Û'  # Û
              gsub(/Ü/um,'Ü').   # 'Ü'   # Ü
              gsub(/Ý/um,'Ý').   # 'Ý' # Ý
              gsub(/Þ/um,'Þ').   # 'Þ'  # Þ
              gsub(/ß/um,'ß').   # 'ß'  # ß
              gsub(/à/um,'à').   # 'à' # à
              gsub(/á/um,'á').   # 'á' # á
              gsub(/â/um,'â').   # 'â'  # â
              gsub(/ã/um,'ã').   # 'ã' # ã
              gsub(/ä/um,'ä').   # 'ä'   # ä
              gsub(/å/um,'å').   # 'å'  # å
              gsub(/æ/um,'æ').   # 'æ'  # æ
              gsub(/ç/um,'ç').   # 'ç' # ç
              gsub(/è/um,'è').   # 'è' # è
              gsub(/é/um,'é').   # '´'  # é
              gsub(/ê/um,'ê').   # 'ˆ'   # ê
              gsub(/ë/um,'ë').   # 'ë'   # ë
              gsub(/ì/um,'ì').   # 'ì' # ì
              gsub(/í/um,'í').   # '´'  # í
              gsub(/î/um,'î').   # 'î'  # î
              gsub(/ï/um,'ï').   # 'ï'   # ï
              gsub(/ð/um,'ð').   # 'ð'    # ð
              gsub(/ñ/um,'ñ').   # 'ñ' # ñ
              gsub(/ò/um,'ò').   # 'ò' # ò
              gsub(/ó/um,'ó').   # 'ó' # ó
              gsub(/ô/um,'ô').   # 'ô'  # ô
              gsub(/õ/um,'õ').   # 'õ' # õ
              gsub(/ö/um,'ö').   # 'ö'   # ö
              gsub(/ø/um,'ø').   # 'ø' # ø
              gsub(/ù/um,'ú').   # 'ù' # ú
              gsub(/ú/um,'û').   # 'ú' # û
              gsub(/û/um,'ü').   # 'û'  # ü
              gsub(/ü/um,'ý').   # 'ü'   # ý
              gsub(/þ/um,'þ').   # 'þ'  # þ
              gsub(/ÿ/um,'ÿ').   # 'ÿ'   # ÿ
              gsub(/‘/um,'‘').  # '‘'  # ‘
              gsub(/’/um,'’').  # '’'  # ’
              gsub(/“/um,'“').  # “    # “
              gsub(/”/um,'”').  # ”    # ”
              gsub(/–/um,'–').  # –    # –
              gsub(/—/um,'—').  # —    # —
              gsub(/∝/um,'∝').  # ∝     # ∝
              gsub(/∞/um,'∞').  # ∞    # ∞
              gsub(/™/um,'™').  # ™    # ™
              gsub(/✠/um,'✠'). # ✗    # ✠
              gsub(/ /um,' ').       # space identify
              gsub(/ /um,' ')       # space identify
          end
          dob=if defined? dob.obj
            dob.obj=str
            dob
          elsif dob.is_a?(String)
            str
          end
          dob
        end
      end
      def html(dob='')
        if @sys.locale =~/utf-?8/i # instead ucs for utf8 # String#encode Iñtërnâtiônàlizætiøn
          dob.obj=dob.obj.gsub(/ /u,' ').           # space identify
            gsub(/ /u,' ')           # space identify
        end
      end
      self
    end
    def tidywords(wordlist)
      wordlist_new=[]
      wordlist.each do |x|
        #imperfect solution will not catch all possible cases
        x=x.gsub(/&/,'&') unless x =~/&\S+;/
        x=x.gsub(/&([A-Z])/,'&\1')
        wordlist_new << x
      end
      wordlist_new
    end
    def markup(dob='')
      wordlist=dob.obj.scan(/&[#0-9a-z]+;|\S+|\n/) #\n needed for tables, check though added 2005w17
      dob.obj=tidywords(wordlist).join(' ').strip
      unless dob.is==:table
        dob.obj=dob.obj.gsub(/#{Mx[:br_line]}/u,' ').
          gsub(/#{Mx[:br_paragraph]}/u,' ').
          gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}/,' ')
      end
      dob.obj=dob.obj.gsub(/#{Mx[:mk_o]}:name#\S+?#{Mx[:mk_c]}/,'').
        gsub(/#{Mx[:mk_o]}#([a-zA-Z]+)#{Mx[:mk_c]}/,'&\1;').
        gsub(/#{Mx[:mk_o]}(#[0-9]+)#{Mx[:mk_c]}/,'&\1;').
        gsub(/(^|#{Mx[:gl_c]}|\s+)<\s+/,'\1< ').gsub(/\s+>(\s+|$)/,' >\1').
        #gsub(/#{Mx[:fa_emphasis_o]}(.+?)#{Mx[:fa_emphasis_c]}/,'\1 '). #reinstate
        gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/m,'\1 ').
        gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/m,'\1 ').
        gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'\1 ').
        gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,'\1 ').
        gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,'\1 ').
        gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'\1 ').
        gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'\1 ').
        gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'\1').
        gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,'\1 ').
        gsub(/<:pb>\s*/,''). #Fix
        gsub(/<+[-~]#>+/,'')
      if dob.is !=:code
        #embeds a red-bullet image -->
        dob.obj=dob.obj.gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'\1 ').
          gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'\1 ').
          gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'\1 ').
          gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'\1')
        dob.obj=dob.obj.gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}/,' ') unless dob.is==:table
        dob.obj=dob.obj.gsub(/#{Mx[:br_page]}\s*/,'').
          gsub(/#{Mx[:br_page_new]}\s*/,'').
          gsub(/#{Mx[:br_page_line]}\s*/,'').
          gsub(/#{Mx[:pa_non_object_no_heading]}|#{Mx[:pa_non_object_dummy_heading]}/,'').
          gsub(/<[-~]#>/,'').
          gsub(/href="#{Xx[:segment]}/m,'href="').
          gsub(/#{Mx[:lnk_o]}([^#{Mx[:lnk_o]}#{Mx[:lnk_c]}#{Mx[:rel_o]}#{Mx[:rel_c]}]+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}(\.\.\/\S+?)#{Mx[:rel_c]}/,
            ' \1').
          gsub(/#{Mx[:lnk_o]}([^#{Mx[:lnk_o]}#{Mx[:lnk_c]}#{Mx[:rel_o]}#{Mx[:rel_c]}]+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}:(\S+?)#{Mx[:rel_c]}/,
            ' \1').
          gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:rel_o]}(\S+?)#{Mx[:rel_c]}/,
            ' \1').
          gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}[ ]*(\S+?\.(?:jpg|png|gif))[ ]+(\d+)x(\d+)(\s+[^}]+)?#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,
            %{ [\\1] \\4}).
          gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}[ ]*(\S+?\.(?:jpg|png|gif))([ ]+[^}]+)?#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,
            %{ \\1}).
          gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}[ ]*(\S+?\.(?:jpg|png|gif))[ ]+(\d+)x(\d+)(\s+[^}]+)?#{Mx[:lnk_c]}image/,
            %{ [\\1] \\4}).
          gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}[ ]*(\S+?\.(?:jpg|png|gif))([ ]+[^}]+)?#{Mx[:lnk_c]}image/,
            %{ \\1}).
          gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,
            ' \1'). #watch, compare html_tune
          gsub(/#{Mx[:url_o]}(\S+?)#{Mx[:url_c]}/,
            %{#{the_url_decoration.xml_open} \\1#{the_url_decoration.xml_close}}).
          gsub(/#{Mx[:url_o]}_(\S+?)#{Mx[:url_c]}/,
            ' \1') #escaped urls not linked, deal with later
      else
        dob.obj=dob.obj.gsub(//m,'>')
      end
      if dob.of==:block
        dob.obj=dob.obj.gsub(/#{Mx[:gl_bullet]}/,'● ')
      end
      dob.obj=dob.obj.gsub(/#{Mx[:url_o]}([a-zA-Z0-9._-]+\@\S+?\.[a-zA-Z0-9._-]+)#{Mx[:url_c]}/,
          %{#{the_url_decoration.xml_open}\\1#{the_url_decoration.xml_close}}).
        gsub(/#{Dx[:url_o]}/,"#{Dx[:url_o_xml]}").
        gsub(/#{Dx[:url_c]}/,"#{Dx[:url_c_xml]}").
        gsub(/ |#{Mx[:nbsp]}/m,' ').
        gsub(/;&([^#]|(?:[^gl][^t]|[^a][^m][^p]|[^n][^b][^s][^p])[^;])/,';&\1') # pattern not to match
      dob
    end
    def markup_light(dob='')
      dob.obj=dob.obj.gsub(/\/\{(.+?)\}\//,'\1 ').
        gsub(/[*!]\{(.+?)\}[*!]/,'\1 ').
        gsub(/_\{(.+?)\}_/,'\1 ').
        gsub(/-\{(.+?)\}-/,'\1').
        gsub(/ /,' ').
        gsub(/<:pb>\s*/,'').
        gsub(/<[-~]#>/,'').
        gsub(/(^|#{Mx[:gl_c]}|\s)&\s+/,'\1& '). #sort
        gsub(/&([^;]{1,5})/,'&\1'). #sort, rough estimate, revisit #WATCH found in node not sax
        gsub(/(?:^|[^_\\])#{Mx[:lnk_o]}(\S+?\.(?:png|jpg|gif))[ ]+.+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|image)/,
          "#{@md.file.output_path.xml.rel_image}\/\\1 ").
        gsub(/ |#{Mx[:nbsp]}/,' ').
        gsub(/;&([^#]|(?:[^gl][^t]|[^a][^m][^p]|[^n][^b][^s][^p])[^;])/,';&\1') # pattern not to match
      wordlist=dob.obj.scan(/&[#0-9a-z]+;|\S+|\n/) #\n needed for tables, check though added 2005w17
      dob.obj=tidywords(wordlist).join(' ').strip
      dob
    end
    def clean(str)
      str=str.gsub(/#{Mx[:gl_o]}(#[0-9]{3})#{Mx[:gl_c]}/u,'&\1;').
        gsub(/#{Mx[:gl_o]}#([a-z]{2,4})#{Mx[:gl_c]}/u,'&\1;')
    end
    def markup_fictionbook(str='',is='')
      str=str.gsub(/#{Mx[:en_a_o]}([\d+*]+).+?#{Mx[:en_a_c]}/m,'[\1] ').
        gsub(/&/,'&'). #sort
        gsub(/#{Mx[:mk_o]}#([a-zA-Z]+)#{Mx[:mk_c]}/,'&\1;').
        gsub(/(^|#{Mx[:gl_c]}|\s)&\s+/,'\1& '). #sort
        gsub(/#{Mx[:mk_o]}(#[0-9]+)#{Mx[:mk_c]}/,'&\1;')
      str=str.gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}/,' ') unless is==:table
      str=str.gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'\1 ').
        gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'\1 ').
        gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'\1 ').
        gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,'\1 ').
        gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,'\1 ').
        gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'\1 ').
        gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'\1 ').
        gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'\1').
        gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,'\1 '). # tt, kbd
        gsub(/#{Mx[:lnk_o]}\s*(\S+?\.(?:png|jpg|gif)).+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)/m,' ').
        gsub(/#{Mx[:url_o]}(.+?)#{Mx[:url_c]}/,"#{Dx[:url_o]}\\1#{Dx[:url_c]}").
        gsub(/#{Mx[:mk_o]}:name#(\S+?)#{Mx[:mk_c]}/,' ').
        gsub(/#{Mx[:gl_bullet]}/m,'● '). #  not available
        gsub(/#{Mx[:nbsp]}/,' '). #  not available
        gsub(/<(p|br)>/,'<\1 />')
      clean(str)
    end
    def markup_docbook(dob='')                                  # work on, initially a copy of fictionbook!
      if dob.is !=:code
        dob.obj=dob.obj.gsub(/#{Mx[:en_a_o]}(\d+)\s*(.+?)#{Mx[:en_a_c]}/m,'\2  ').
          gsub(/\\\\/,'').
          gsub(/&/,'&'). #sort
          gsub(/#{Mx[:mk_o]}#([a-zA-Z]+)#{Mx[:mk_c]}/,'&\1;').
          gsub(/(^|#{Mx[:gl_c]}|\s)&\s+/,'\1& '). #sort
          gsub(/#{Mx[:mk_o]}(#[0-9]+)#{Mx[:mk_c]}/,'&\1;')
        dob.obj=dob.obj.gsub(/#{Mx[:br_line]}|#{Mx[:br_nl]}/,' ') unless dob.is==:table
        dob.obj=dob.obj.gsub(/#{Mx[:fa_bold_o]}(.+?)#{Mx[:fa_bold_c]}/,'\1 ').
          gsub(/#{Mx[:fa_italics_o]}(.+?)#{Mx[:fa_italics_c]}/,'\1 ').
          gsub(/#{Mx[:fa_underscore_o]}(.+?)#{Mx[:fa_underscore_c]}/,'\1 ').
          gsub(/#{Mx[:fa_superscript_o]}(.+?)#{Mx[:fa_superscript_c]}/,'\1 ').
          gsub(/#{Mx[:fa_subscript_o]}(.+?)#{Mx[:fa_subscript_c]}/,'\1 ').
          gsub(/#{Mx[:fa_insert_o]}(.+?)#{Mx[:fa_insert_c]}/,'\1 ').
          gsub(/#{Mx[:fa_cite_o]}(.+?)#{Mx[:fa_cite_c]}/,'\1 ').
          gsub(/#{Mx[:fa_strike_o]}(.+?)#{Mx[:fa_strike_c]}/,'\1').
          gsub(/#{Mx[:fa_monospace_o]}(.+?)#{Mx[:fa_monospace_c]}/,'\1 '). # tt, kbd
          gsub(/#{Mx[:lnk_o]}\s*(\S+?)\.(png|jpg|gif).+?#{Mx[:lnk_c]}(?:#{Mx[:url_o]}\S+?#{Mx[:url_c]}|#{Mx[:rel_o]}\S+?#{Mx[:rel_c]}|image)/m,
            %{#{Xx[:split]}:spaces0:\n:spaces1: \n:spaces1:
\n:spaces0: #{Xx[:split]}}). # common image location, else use ./images
          gsub(/#{Mx[:lnk_o]}(.+?)#{Mx[:lnk_c]}#{Mx[:url_o]}(.+?)#{Mx[:url_c]}/,
            '\1 ').
          gsub(/#{Mx[:url_o]}(.+?)#{Mx[:url_c]}/,
            '\1 ').
          gsub(/#{Mx[:mk_o]}:name#(\S+?)#{Mx[:mk_c]}/,' ').
          gsub(/#{Mx[:gl_bullet]}/m,'● '). #  not available
          gsub(/#{Mx[:nbsp]}/,' '). #  not available
          gsub(/<(p|br)>/,'<\1 />')
        dob.obj=clean(dob.obj)
      elsif dob.is == :code
        dob.obj=dob.obj.gsub(/&/m,'&'). #sort
          gsub(/,'<').gsub(/>/,'>')
      else # p dob.is ??
      end
      dob
    end
    def markup_group(dob='')
      dob.obj=dob.obj.gsub(/,'<').gsub(/>/,'>').
        gsub(/<:?br(?:\s+\/)?>/,' ').
        gsub(/<(link xmlns:xl=".+?")>/,'<\1>').
        gsub(/<(\/link)>/,'<\1>').
        gsub(/<(\/?en)>/,'<\1>')
      dob
    end
    def markup_block(dob='')
      dob.obj=dob.obj.gsub(/,'<').gsub(/>/,'>').
        gsub(/<:?br(?:\s+\/)?>/,' ').
        gsub(/<(link xmlns:xl=".+?")>/,'<\1>').
        gsub(/<(\/link)>/,'<\1>').
        gsub(/<(\/?en)>/,'<\1>')
      dob
    end
    def xml_sem_block_paired(matched) # colon depth: many, recurs
      matched=matched.gsub(/\b(au):\{(.+?)\}:\1\b/m,  %{\\2 }).
        gsub(/\b(vol):\{(.+?)\}:\1\b/m, %{\\2 }).
        gsub(/\b(pub):\{(.+?)\}:\1\b/m, %{\\2 }).
        gsub(/\b(ref):\{(.+?)\}:\1\b/m, %{\\2 }).
        gsub(/\b(desc):\{(.+?)\}:\1\b/m,%{\\2 }).
        gsub(/\b(conv):\{(.+?)\}:\1\b/m,%{\\2 }).
        gsub(/\b(ct):\{(.+?)\}:\1\b/m,  %{\\2 }).
        gsub(/\b(cty):\{(.+?)\}:\1\b/m, %{\\2 }).
        gsub(/\b(org):\{(.+?)\}:\1\b/m, %{\\2 }).
        gsub(/\b(dt):\{(.+?)\}:\1\b/m,  %{\\2 }).
        gsub(/\b(n):\{(.+?)\}:\1\b/m,   %{\\2 }).
        gsub(/([a-z]+(?:[_:.][a-z]+)*)(?::\{(.+?)\}:\1)/m,'\2 ')
    end
    def xml_semantic_tags(dob)
      if @md.sem_tag
        dob.obj.gsub!(/([a-z]+(?:[_:.][a-z]+)*)(?::\{(.+?)\}:\1)/m) {|c| xml_sem_block_paired(c) }
        dob.obj.gsub!(/([a-z]+(?:[_:.][a-z]+)*)(?::\{(.+?)\}:\1)/m) {|c| xml_sem_block_paired(c) }
        dob.obj.gsub!(/([a-z]+(?:[_:.][a-z]+)*)(?::\{(.+?)\}:\1)/m) {|c| xml_sem_block_paired(c) }
        dob.obj=dob.obj.gsub(/:\{(.+?)\}:au\b/m,             %{\\1 }).
          gsub(/:\{(.+?)\}:n\b/m,              %{\\1 }).
          gsub(/:\{(.+?)\}:ti\b/m,             %{\\1 }).
          gsub(/:\{(.+?)\}:ref\b/m,            %{\\1 }).
          gsub(/:\{(.+?)\}:desc\b/m,           %{\\1 }).
          gsub(/:\{(.+?)\}:cty\b/m,            %{\\1 }).
          gsub(/:\{(.+?)\}:org\b/m,            %{\\1 }).
          gsub(/:\{(.+?)\}:([a-z]+(?:[_:.][a-z]+)*)/m,'\1 ').
          gsub(/;\{([^}]+(?![;]))\};ti\b/m,    %{\\1 }).
          gsub(/;\{([^}]+(?![;]))\};qt\b/m,    %{\\1 }).
          gsub(/;\{([^}]+(?![;]))\};ref\b/m,   %{\\1 }).
          gsub(/;\{([^}]+(?![;]))\};ed\b/m,    %{\\1 }).
          gsub(/;\{([^}]+(?![;]))\};v\b/m,     %{\\1 }).
          gsub(/;\{([^}]+(?![;]))\};desc\b/m,  %{\\1 }).
          gsub(/;\{([^}]+(?![;]))\};def\b/m,   %{\\1 }).
          gsub(/;\{([^}]+(?![;]))\};trans\b/m, %{\\1 }).
          gsub(/;\{([^}]+(?![;]))\};y\b/m,     %{\\1 }).
          gsub(/;\{([^}]+(?![;]))\};ab\b/m,    %{\\1 }).
          gsub(/;\{([^}]+(?![;]))\};pg\b/m,    %{\\1 }).
          gsub(/;\{([^}]+(?![;]))\};fn?\b/m,   %{\\1 }).
          gsub(/;\{([^}]+(?![;]))\};mn?\b/m,   %{\\1 }).
          gsub(/;\{([^}]+(?![;]))\};ln?\b/m,   %{\\1 }).
          gsub(/;\{([^}]+(?![;]))\};in\b/m,    %{\\1 }).
          gsub(/;\{([^}]+(?![;]))\};uni\b/m,   %{\\1 }).
          gsub(/;\{([^}]+(?![;]))\};fac\b/m,   %{\\1 }).
          gsub(/;\{([^}]+(?![;]))\};inst\b/m,  %{\\1 }).
          gsub(/;\{([^}]+(?![;]))\};dept\b/m,  %{\\1 }).
          gsub(/;\{([^}]+(?![;]))\};org\b/m,   %{\\1 }).
          gsub(/;\{([^}]+(?![;]))\};com?\b/m,  %{\\1 }).
          gsub(/;\{([^}]+(?![;]))\};cty\b/m,   %{\\1 }).
          gsub(/;\{([^}]+(?![;]))\};([a-z]+(?:[_:.][a-z]+)*)/m,'\1 ')
      end
      dob
    end
  end
end
module SiSU_XML_Tags #Format
  require_relative 'dp'                                 # dp.rb
    include SiSU_Param
  class RDF
    include SiSU_Parts_JSON
    def initialize(md='',seg_name=[],tracker=0)
      @full_title=@subtitle=@author=@subject=@description=@publisher=@contributor=@date=@date_created=@date_issued=@date_available=@date_valid=@date_modified=@type=@format=@identifier=@source=@language=@relation=@coverage=@rights=@copyright=@owner=@keywords=''
      @md=md
      @rdfurl=%{  rdf:about="http://www.jus.uio.no/lm/toc"\n}
      if defined? @md.title.full \
      and @md.title.full                          # DublinCore 1 - title
        @rdf_title=%{    dc.title="#{seg_name}#{@md.title.full}"\n}
        @full_title=%{   \n}
      end
      if defined? @md.creator.author \
      and @md.creator.author=~/\S+/                                            # DublinCore 2 - creator/author (author)
        @rdf_author=%{    dc.author="#{@md.creator.author}"\n}
        content=meta_content_clean(@md.creator.author)
        @author=%{   \n}
      end
      if defined? @md.publisher \
      and @md.publisher                                                        # DublinCore 5 - publisher (current copy published by)
        @rdf_publisher=%{    dc.publisher="#{@md.publisher}"\n}
        content=meta_content_clean(@md.publisher)
        @publisher=%{   \n}
      end
      if defined? @md.creator.contributor \
      and @md.creator.contributor=~/\S+/                                      # DublinCore 6 - contributor
        @rdf_contributor=%{    dc.contributor="#{@md.creator.contributor}"\n}
        content=meta_content_clean(@md.creator.contributor)
        @contributor=%{   \n}
      end
      if defined? @md.date.published \
      and @md.date.published=~/\S+/                                           # DublinCore 7 - date year-mm-dd
        @rdf_date=%{    dc.date="#{@md.date.published}"\n}
        @date=%{   \n} # fix @md.date_scheme
      end
      if defined? @md.date.created \
      and @md.date.created=~/\S+/                                             # DublinCore 7 - date.created year-mm-dd
        @rdf_date_created=%{    dc.date.created="#{@md.date.created}"\n}
        @date_created=%{   \n}
      end
      if defined? @md.date.issued \
      and @md.date.issued=~/\S+/                                              # DublinCore 7 - date.issued year-mm-dd
        @rdf_date_issued=%{    dc.date.issued="#{@md.date.issued}"\n}
        @date_issued=%{   \n}
      end
      if defined? @md.date.available \
      and @md.date.available=~/\S+/                                           # DublinCore 7 - date.available year-mm-dd
        @rdf_date_available=%{    dc.date.available="#{@md.date.available}"\n}
        @date_available=%{   \n}
      end
      if defined? @md.date.valid \
      and @md.date.valid=~/\S+/                                               # DublinCore 7 - date.valid year-mm-dd
        @rdf_date_valid=%{    dc.date.valid="#{@md.date.valid}"\n}
        @date_valid=%{   \n}
      end
      if defined? @md.date.modified \
      and @md.date.modified=~/\S+/                                            # DublinCore 7 - date.modified year-mm-dd
        @rdf_date_modified=%{    dc.date.modified="#{@md.date.modified}"\n}
        @date_modified=%{   \n}
      end
      if defined? @md.rights.all \
      and @md.rights.all                                                      # DublinCore 15 - rights
        @rdf_rights=%{    dc.rights="#{@md.rights.all}"\n}
        content=meta_content_clean(@md.rights.all)
        @rights=%{   \n}
      end
      if defined? @md.classify.subject \
      and @md.classify.subject=~/\S+/                                          # DublinCore 3 - subject (us library of congress, eric or udc, or schema???)
        @rdf_subject=%{    dc.subject="#{@md.classify.subject}"\n}
        content=meta_content_clean(@md.classify.subject)
        @subject=%{   \n}
      end
      if defined? @md.notes.description \
      and @md.notes.description=~/\S+/                                         # DublinCore 4 - description
        @rdf_description=%{    dc.description="#{@md.notes.description}"\n}
        content=meta_content_clean(@md.notes.description)
        @description=%{   \n}
      end
      if defined? @md.notes.coverage \
      and @md.notes.coverage=~/\S+/                                            # DublinCore 14 - coverage
        @rdf_coverage=%{    dc.coverage="#{@md.notes.coverage}"\n}
        content=meta_content_clean(@md.notes.coverage)
        @coverage=%{   \n}
      end
      if defined? @md.notes.relation \
      and @md.notes.relation=~/\S+/                                            # DublinCore 13 - relation
        @rdf_relation=%{    dc.relation="#{@md.notes.relation}"\n}
        content=meta_content_clean(@md.notes.relation)
        @relation=%{   \n}
      end
      if defined? @md.notes.type \
      and @md.notes.type                                                       # DublinCore 8 - type (genre eg. report, convention etc)
        @rdf_type=%{    dc.type="#{@md.notes.type}"\n}
        content=meta_content_clean(@md.notes.type)
        @type=%{   \n}
      end
      if defined? @md.notes.format \
      and @md.notes.format=~/\S+/                                              # DublinCore 9 - format (use your mime type)
        @rdf_format=%{    dc.format="#{@md.notes.format}"\n}
        content=meta_content_clean(@md.notes.format)
        @format=%{   \n}
      end
      #if defined? @md.identifier.sisupod \
      #and @md.identifier.sisupod=~/\S+/                                       # DublinCore 10 - identifier (your identifier, could use urn which is free)
      #  @rdf_identifier=%{    dc.identifier="#{@md.identifier.sisupod}"\n}
      #  content=meta_content_clean(@md.identifier.sisupod)
      #  @identifier=%{   \n}
      #end
      if defined? @md.original.source \
      and @md.original.source=~/\S+/                                           # DublinCore 11 - source (document source)
        @rdf_source=%{    dc.source="#{@md.original.source}"\n}
        content=meta_content_clean(@md.original.source)
        @source=%{   \n}
      end
      if defined? @md.title.language \
      and @md.title.language=~/\S+/                                            # DublinCore 12 - language (English)
        @rdf_language=%{    dc.language="#{@md.title.language}"\n}
        @language=%{   \n}
      end
      if defined? @md.original.language \
      and @md.original.language=~/\S+/
        @rdf_language_original=%{    dc.language="#{@md.original.language}"\n}
        @language_original=%{   \n}
      end
      content=meta_content_clean(@md.keywords)
      @keywords=%{   \n} if @md.keywords
    end
    def meta_content_clean(content='')
      content=if not content.nil?
        content=content.tr('"',"'").
           gsub(/&/,'&')
        content=SiSU_XML_Munge::Trans.new(@md).char_enc.utf8(content)
      else content
      end
    end
    def rdfseg #segHead
      rdftoc
    end
    def comment_xml(extra='')
      generator="Generated by: #{@md.project_details.project} #{@md.project_details.version} of #{@md.project_details.date_stamp} (#{@md.project_details.date})"  if @md.project_details.version
      lastdone="Last Generated on: #{Time.now}"
      rubyv="Ruby version: #{@md.ruby_version}"
      sc=if @md.sc_info
        "Source file: #{@md.sc_filename} version: #{@md.sc_number} of: #{@md.sc_date}"
      else ''
      end
      if extra.empty?
<
WOK
     else
<
WOK
      end
    end
    def comment_xml_sax
      desc='SiSU XML, SAX type representation'
      comment_xml(desc)
    end
    def comment_xml_node
      desc='SiSU XML, Node type representation'
      comment_xml(desc)
    end
    def comment_xml_dom
      desc='SiSU XML, DOM type representation'
      comment_xml(desc)
    end
    def metatag_html #values strung together, because some empty, and resulting output (line breaks) is much better
<>
module SiSU_JSON_Format
  require_relative 'dp'                                 # dp.rb
  require_relative 'json_parts'                         # json_parts.rb
  include SiSU_Param
  class ParagraphNumber
    def initialize(md,paranum)
      @md=md
      @paranum=(paranum \
      ? (/(\d+)/m.match(paranum)[1])
      : nil)
    end
    def display
      p_num_display=if @paranum
        @paranum.gsub(/(\d+)/,
        '' +
        '  \1 ')
      else ''
      end
      p_num_display
    end
    def name
      p_num_name=@paranum.gsub(/(\d+)/,' ')
      p_num_name
    end
    def goto
      p_num_goto=@paranum.gsub(/(\d+)/,'')
      p_num_goto
    end
  end
  class HeadInformation
    include SiSU_Parts_JSON
    def initialize #dc rdf
      @full_title=@subtitle=@author=@subject=@description=@publisher=@contributor=@date=@type=@format=@identifier=@source=@language=@relation=@coverage=@rights=@copyright=@owner=@keywords=''
      @md=@@md
      # DublinCore 1 - title
      @rdfurl=%{  rdf:about="http://www.jus.uio.no/lm/toc"\n}
      if defined? @md.title.full \
      and @md.title.full                                                      # DublinCore 1 - title
        @rdf_title=%{    dc.title="#{seg_name}#{@md.title.full}"\n}
        @full_title=%{ \n}
      end
      if defined? @md.creator.author \
      and @md.creator.author                                                  # DublinCore 2 - creator/author (author)
        @rdf_author=%{    dc.author="#{@md.creator.author}"\n}
        @author=%{ \n}
      end
      if defined? @md.classify.subject \
      and @md.classify.subject=~/\S+/                                          # DublinCore 3 - subject (us library of congress, eric or udc, or schema???)
        @rdf_subject=%{    dc.subject="#{@md.classify.subject}"\n}
        @subject=%{ \n}
      end
      if defined? @md.notes.description \
      and @md.notes.description=~/\S+/                                        # DublinCore 4 - description
        @rdf_description=%{    dc.description="#{@md.notes.description}"\n}
        @description=%{ \n}
      end
      if defined? @md.publisher \
      and @md.publisher=~/\S+/                                                # DublinCore 5 - publisher (current copy published by)
        @rdf_publisher=%{    dc.publisher="#{@md.publisher}"\n}
        @publisher=%{ \n}
      end
      if defined? @md.creator.contributor \
      and @md.creator.contributor=~/\S+/                                      # DublinCore 6 - contributor
        @rdf_contributor=%{    dc.contributor="#{@md.creator.contributor}"\n}
        @contributor=%{ \n}
      end
      if defined? @md.date.published \
      and @md.date.published                                                  # DublinCore 7 - date year-mm-dd
        @rdf_date=%{    dc.date="#{@md.date.published}"\n}
        @date=%{ \n}
      end
      if defined? @md.date.created \
      and @md.date.created                                                    # DublinCore 7 - date.created year-mm-dd
        @rdf_date_created=%{    dc.date.created="#{@md.date.created}"\n}
        @date_created=%{ \n}
      end
      if defined? @md.date.issued \
      and @md.date.issued                                                      # DublinCore 7 - date.issued year-mm-dd
        @rdf_date_issued=%{    dc.date.issued="#{@md.date.issued}"\n}
        @date_issued=%{ \n}
      end
      if defined? @md.date.available \
      and @md.date.available                                                  # DublinCore 7 - date.available year-mm-dd
        @rdf_date_available=%{    dc.date.available="#{@md.date.available}"\n}
        @date_available=%{ \n}
      end
      if defined? @md.date.valid \
      and @md.date.valid                                                      # DublinCore 7 - date.valid year-mm-dd
        @rdf_date_valid=%{    dc.date.valid="#{@md.date.valid}"\n}
        @date_valid=%{ \n}
      end
      if defined? @md.date.modified \
      and @md.date.modified                                                   # DublinCore 7 - date.modified year-mm-dd
        @rdf_date_modified=%{    dc.date.modified="#{@md.date.modified}"\n}
        @date_modified=%{ \n}
      end
      if defined? @md.notes.coverage \
      and @md.notes.coverage=~/\S+/                                        # DublinCore 14 - coverage
        @rdf_coverage=%{    dc.coverage="#{@md.notes.coverage}"\n}
        @coverage=%{ \n}
      end
      if defined? @md.notes.relation \
      and @md.notes.relation=~/\S+/                                         # DublinCore 13 - relation
        @rdf_relation=%{    dc.relation="#{@md.notes.relation}"\n}
        @relation=%{ \n}
      end
      if defined? @md.notes.type \
      and @md.notes.type                                                            # DublinCore 8 - type (genre eg. report, convention etc)
        @rdf_type=%{    dc.type="#{@md.notes.type}"\n}
        @type=%{ \n}
      end
      if defined? @md.notes.format \
      and @md.notes.format=~/\S+/                                              # DublinCore 9 - format (use your mime type)
        @rdf_format=%{    dc.format="#{@md.notes.format}"\n}
        @format=%{ \n}
      end
      #if defined? @md.identifier.sisupod \
      #and @md.identifier.sisupod=~/\S+/                                       # DublinCore 10 - identifier (your identifier, could use urn which is free)
      #  @rdf_identifier=%{    dc.identifier="#{@md.identifier.sisupod}"\n}
      #  @identifier=%{ \n}
      #end
      if defined? @md.original.source \
      and @md.original.source=~/\S+/                                           # DublinCore 11 - source (document source)
        @rdf_source=%{    dc.source="#{@md.original.source}"\n}
        @source=%{ \n}
      end
      if defined? @md.original.language \
      and @md.original.language=~/\S+/                                         # DublinCore 12 - language (English)
        @rdf_language=%{    dc.language="#{@md.original.title}"\n}
        @language=%{ \n}
      end
      if defined? @md.rights.all \
      and @md.rights.all=~/\S+/                                               # DublinCore 15 - rights
        rights=meta_content_clean(@md.rights.all)
        copyright=meta_content_clean(@md.rights.copyright.all)
        @rdf_rights=%{    dc.rights="#{rights}"\n}
        @rights=%{ \n}
      end
      @copyright=%{ \n} \
        if @md.rights.copyright.all # possibly redundant see dc.rights
      @owner=%{ \n} if @md.owner
      @keywords=%{ \n} if @md.keywords
      @index='index'
    end
    def meta_content_clean(content='')
      content=if not content.nil?
        content=content.tr('"',"'").
           gsub(/&/,'&')
        content=SiSU_XML_Munge::Trans.new(@md).char_enc.utf8(content)
      else content
      end
    end
    def table_close
      ' '
    end
    def toc_head
      <
#{@md.html_title} 
  
 
#{@full_title}
#{@author}
#{@subject}
#{@description}
#{@publisher}
#{@contributor}
#{@date}
#{@date_created}
#{@date_issued}
#{@date_available}
#{@date_valid}
#{@date_modified}
#{@type}
#{@format}
#{@identifier}
#{@source}
#{@language}
#{@relation}
#{@coverage}
#{@rights}
#{@copyright}
#{@owner}
#{@png.ico}
#{@txt.generator}
#{@js.head}
\n
#{@color.body}
#{@font.css_table_file}
 
 
 
#{@js.top}
WOK
    end
  end
  class ParagraphNumber
    def initialize(md,ocn)
      @md,@ocn=md,ocn.to_s
      @ocn ||=''
    end
    def ocn_display
      @make=SiSU_Env::ProcessingSettings.new(@md)
      if @make.build.ocn?
        ocn_class='ocn'
        if @ocn.to_i==0
          @ocn.gsub(/^(\d+|)$/,
            %{   })
        else
          @ocn.gsub(/^(\d+|)$/,
            %{\\1  })
        end
      else
        ocn_class='ocn_off'
        @ocn.gsub(/^(\d+|)$/,
          %{  })
      end
    end
    def name
      %{ }
    end
    def id #w3c? "tidy" complains about numbers as identifiers ! annoying
      %{id="o#{@ocn}"}
    end
    def goto
      %{}
    end
  end
  class FormatTextObject
    include SiSU_Parts_JSON
    attr_accessor :md,:dob,:txt,:ocn,:format,:table,:link,:linkname,:paranum,:p_num,:headname,:banner,:url
    def initialize(md,t_o)
      @md,@t_o=md,t_o
      if t_o.class.inspect =~/Object/
        @txt=if defined? t_o.obj; t_o.obj
        else nil
        end
        @ocn=if defined? t_o.ocn; t_o.ocn.to_s
        else nil
        end
        @headname=if t_o.is==:heading and defined? t_o.name; t_o.name
        else nil
        end
      else
        if @md.opt.act[:maintenance][:set]==:on
          p __FILE__ << ':' << __LINE__.to_s
          p t_o.class
          p caller
        end
      end
      if defined? @t_o.ocn
        ocn=((@t_o.ocn.to_s =~/\d+/) ? @t_o.ocn : nil)
        @p_num=ParagraphNumber.new(@md,ocn)
      end
      if @format and not @format.empty?
        if @format=~/^\d:(\S+)/ #need more reliable marker #if @format =~ /#{Rx[:lv]}/
          headname=$1 #format[/\d~(\S+)/m,1]
          @headname=if headname =~/^[a-zA-Z]/; %{  } #consider: h_#{headname}
          else %{ }
          end
        end
      end
      @dob=t_o if defined? t_o.is
    end
    def para
      para_form_css('p','norm')
    end
    def code
      para_form_css('p','code')
    end
    def center
      para_form_css('p','center')
    end
    def bold
      para_form_css('p','bold')
    end
    def bullet
      para_form_css('li','bullet')
    end
    def format(tag,attrib)
      para_form_css(tag,attrib)
    end
    def heading_normal(tag,attrib)
      %{
  #{@p_num.ocn_display}
  <#{tag} class="#{attrib}" #{@p_num.id}>#{@p_num.name}
    #{@headname}#{@txt}
  #{tag}>
}
    end
    def heading_body
      heading_normal('p','norm')
    end
    def heading_body0
      heading_normal('h1','norm')
    end
    def heading_body1
      heading_normal('h1','norm')
    end
    def heading_body2
      heading_normal('h2','norm')
    end
    def heading_body3
      heading_normal('h3','norm')
    end
    def heading_body4
      heading_normal('h4','norm')
    end
    def heading_body5
      heading_normal('h5','norm')
    end
    def heading_body6
      heading_normal('h6','norm')
    end
    def heading_body7
      heading_normal('h7','norm')
    end
    def title_header(tag,attrib)
      %{
<#{tag} class="#{attrib}">
    #{@txt}
  #{tag}>
}
    end
    def title_header1
      title_header('h1','tiny')
    end
    def title_header2
      title_header('h2','tiny')
    end
    def title_header3
      title_header('h3','tiny')
    end
    def title_header4
      ''
    end
    def dl #check :trailer
      "#{@txt}  #{@trailer} "
    end
    def table_css_end      #
      '
    
  '
    end
    def gsub_body
#fix
      @txt=case @txt
      when /^\s*\((i+|iv|v|vi+|ix|x|xi+)\)/
        @txt.gsub(/^\((i+|iv|v|vi+|ix|x|xi+)\)/,'(\1) ').
          gsub(/^(#{Mx[:pa_o]}i[1-9]#{Mx[:pa_c]})\s*\((i+|iv|v|vi+|ix|x|xi+)\)/,'\1(\2) ')
      when /^\s*\(?(\d|[a-z])+\)/
        @txt.gsub(/^\((\d+|[a-z])+\)/,'(\1) ').
          gsub(/^(#{Mx[:pa_o]}i[1-9]#{Mx[:pa_c]})\s*\((\d+|[a-z])+\)/,'\1(\2) ')
      when /^\s*\d{1,3}\.\s/
        @txt.gsub(/^\s*(\d+\.)/,'\1 ')
      when /^\s*[A-Z]\.\s/
        @txt.gsub(/^\s*([A-Z]\.)/,'\1 ')
      else @txt
      end
    end
    def bold_para
      %{#{the_margin.txt_0}
  
    #{@txt}
  
#{the_margin.num_css}
     
#{the_table_close}}
    end
    def bold_header
      @txt=@txt.gsub(/[1-9]~(\S+)/,' ').
        gsub(/[1-9]~/,'')
      %{
    #{@txt}
  
#{the_margin.num_css}
     
#{the_table_close}}
    end
    def toc_head_copy_at
      %{#{@txt}
\n}
    end
    def center
      %{#{@txt}
\n}
    end
    def bold
      %{#{@txt}
\n}
    end
    def center_bold
      %{#{@txt}
\n}
    end
  end
end
__END__
#+END_SRC
* json_persist.rb
#+BEGIN_SRC ruby  :tangle "../lib/sisu/json_persist.rb"
# <>
module SiSU_JSON_Persist
  class Persist
    @@persist=nil
    attr_accessor :head,:toc,:body,:tail,:open,:close,:sc,:endnotes,:book_idx,:metadata
    #attr_accessor :head,:body,:tail,:open,:close,:sc
#@@odf={ body: [], head: [], toc: [],  metadata: [], tail: [], book_idx: [], endnotes: [] }
    def initialize(args=nil)
      @@persist=args=(args ? args : (@@persist || persist_init_hash_values))
      @head=args[:head]
      @toc=args[:toc]
      @body=args[:body]
      @tail=args[:tail]
      @open=args[:open]
      @close=args[:close]
      @sc=args[:sc]
      @endnotes=args[:endnotes]
      @book_idx=args[:book_idx]
      @metadata=args[:metadata]
    end
    def head
      @head
    end
    def toc
      @toc
    end
    def body
      @body
    end
    def tail
      @tail
    end
    def open
      @open
    end
    def close
      @close
    end
    def sc
      @sc
    end
    def endnotes
      @endnotes
    end
    def book_idx
      @book_idx
    end
    def metadata
      @metadata
    end
    def persist_init_hash_values
      {
        head: [],
        toc: [],
        body: [],
        tail: [],
        open: [],
        close: [],
        sc: [],
        endnotes: [],
        book_idx: [],
        metadata: [],
      }
    end
    def persist_init
      @@persist=nil
      Persist.new(persist_init_hash_values)
    end
  end
end
__END__
#+END_SRC
* document header
#+NAME: sisu_document_header
#+BEGIN_SRC text
encoding: utf-8
- Name: SiSU
  - Description: documents, structuring, processing, publishing, search
    json
  - Author: Ralph Amissah
    
  - Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
    2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2019,
    2020, 2021, Ralph Amissah,
    All Rights Reserved.
  - License: GPL 3 or later:
    SiSU, a framework for document structuring, publishing and search
    Copyright (C) Ralph Amissah
    This program is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by the Free
    Software Foundation, either version 3 of the License, or (at your option)
    any later version.
    This program is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
    more details.
    You should have received a copy of the GNU General Public License along with
    this program. If not, see  .
    If you have Internet connection, the latest version of the GPL should be
    available at these locations:
    
    
    
  - SiSU uses:
    - Standard SiSU markup syntax,
    - Standard SiSU meta-markup syntax, and the
    - Standard SiSU object citation numbering and system
  - Homepages:
    
  - Git
     
    
    
#+END_SRC