start =
  element config {
    # Option scope
    element optionscope {
      attribute type { "GLOBAL" | "ENTRYTYPE" | "ENTRY" | "NAMELIST" | "NAME" },
      element option {
        attribute datatype { "boolean" | "integer" | "string" | "xml" },
        # Applies to ENTRY, NAMELIST and NAME scope
        # Only set for meta-options and if defined, what biber should split
        # the option into on reading it
        attribute backendin {xsd:string}?,
        # Applies to ENTRY, NAMELIST and NAME scope
        # Determines whether biber will write the option to its ouput (e.g.
        # .bbl) because biblatex needs to know the value.
        attribute backendout {xsd:boolean}?,
        xsd:string
      }+
    }* &
    element clrmacros           { "0" | "1" }? &
    element collate             { "0" | "1" }? &
    element collate_options     {
      element option {
        attribute name { text } &
        attribute value { text }
      }+
    }? &
    # datafield sets
    element datafieldset {
      attribute name { text },
      element member {
        ((attribute fieldtype { dmfieldtype }?,
          attribute datatype { dmdatatype }?) |
        attribute field { text }?),
        empty
      }+
    }* &
           
    # Annotation marker
    element annotation_marker { text }? &
    # Can't specify the config file location in the config file ...
    # element configfile          { text }? & 
    element convert_control     { "0" | "1" }? &
    element dot_include         { text }? &
    # Data model specification (mainly for tool mode)
    datamodel? &
    element decodecharsset      { text }? &
    element debug               { "0" | "1" }? &
    element fastsort            { "0" | "1" }? &
    element fixinits            { "0" | "1" }? &
    # Would never want this in the config file
    #  element help                { "0" | "1" }? &
    inheritance? &
    element input_encoding      { text }? &
    element listsep             { text }? &
    element logfile             { text }? &
    element mincrossrefs        { xsd:unsignedByte }? &
    element mssplit             { text }? &
    element namesep             { text }? &
    # Can't specify not to use a config file in the config file ...
    #  element noconf              { "0" | "1" }? &
    element nodieonerror         { "0" | "1" }? &
    element nolog                { "0" | "1" }? &
    # noinit specification
    element noinits {
      element noinit {
        attribute value { xsd:string },
        empty
      }+
    }? &
    # nolabel specification
    element nolabels {
      element nolabel {
        attribute value { xsd:string },
        empty
      }+
    }? &
    # nosort specification
    element nosort     {
      element option {
        attribute name { text } &
        attribute value { text }
      }+
    }? &
    element nostdmacros          { "0" | "1" }? &
    element onlylog              { "0" | "1" }? &
    element others_string        { text }? &
    element output_align         { "0" | "1" }? &
    element output_all_macrodefs { "0" | "1" }? &
    element output_annotation_marker { text }? &
    element output_directory     { text }? &
    element output_encoding      { text }? &
    element output_fieldcase     { "upper" | "lower" | "title" }? &
    element output_field_replace { text }? &
    element output_file          { text }? &
    element output_format        { "bibtex" | "bbl" | "biblatexml" | "dot" }? &
    element output_indent        { xsd:unsignedByte }? &
    element output_listsep       { text }? &
    element output_namesep       { text }? &
    element output_no_macrodefs  { "0" | "1" }? &
    element output_resolve_xdata { "0" | "1" }? &
    element output_resolve_crossrefs { "0" | "1" }? &
    element output_resolve_sets { "0" | "1" }? &
    element output_safechars     { "0" | "1" }? &
    element output_safecharsset  { "base" | "full" }? &
    element output_xdatamarker   { text }? &
    element output_xdatasep      { text }? &
    element output_xname         { "0" | "1" }? &
    element output_xnamesep      { text }? &
    element quiet                { "0" | "1" }? &
    element recodedata           { text }? &
    element sortcase             { "0" | "1" }? &
    translit* &
    labelalphanametemplate* &
    labelalphatemplate? &
    uniquenametemplate* &
    sortingnamekeytemplate? &
    sortingtemplate? &
    # presort default strings for different entry types
    element presort {
      attribute type { text }?,
      text
    }* &
    # excludes of certain fields for sorting for specified types
    element sortexclusion {
      attribute type { text },
      element exclusion { text }+
    }* &
    # forcibly includes certain fields excluded by sortexclusion for sorting for specified types
    element sortinclusion {
      attribute type { text },
      element inclusion { text }+
    }* &
    element sortlocale           { text }? &
    element sortupper            { "0" | "1" }? &
    element sourcemap            {
      element maps {
        attribute datatype { "bibtex" | "biblatexml" },
        attribute map_overwrite { "0" | "1" }?,
        map+
      }+
    }? &
    element ssl-nointernalca     { "0" | "1" }? &
    element ssl-noverify-host    { "0" | "1" }? &
    element tool                 { "0" | "1" }? &
    element tool_config          { text }? &
    element trace                { "0" | "1" }? &
    element validate_config      { "0" | "1" }? &
    element validate_control     { "0" | "1" }? &
    element validate_datamodel   { "0" | "1" }? &
    # Meaningless in the config file
    #  element version              { "0" | "1" }? &
    element wraplines            { "0" | "1" }? &
    element xdatamarker          { text }? &
    element xdatasep             { text }? &
    element xname                { "0" | "1" }? &
    element xnamesep             { text }?
  }

datamodel =
  element datamodel {
    # Constants
    element constants {
      element constant {
        attribute type { "string" | "list" }?,
        attribute name { text },
        text
      }+
    },
    # Valid entrytypes
    element entrytypes {
      element entrytype {
        # Some entrytypes should be completely skipped on output (XDATA etc.)
        attribute skip_output { "true" }?,
        text
      }+
    },
    # BibLaTeX field types. Biber uses this to determine how to output various types
    # to the .bbl
    element fields {
      element field {
        # fieldtype is "field" or "list"
        attribute fieldtype { dmfieldtype },
        # format is a specification of the format of the field. If not specified, field contents
        # are just as is. 
        attribute format { "xsv" }?,
        # datatype of field content
        attribute datatype { dmdatatype },
        # Are we allowed to output a null field value to the .bbl for this field?
        attribute nullok { "true" }?,
        # Should this field be skipped and not output to the .bbl?
        attribute skip_output { "true" }?,
        # Field can be used as a label? This auto-generates some defaults in biblatex
        attribute label { "true" }?,
        text
      }+
    },
    # Allowable fields for entrytypes
    # Only one specification per entrytype: even though it might be nice to have several 
    # so that one could share information, this would be hard to manage and confusing as it
    # not be visible in one place which fields were valid for an entrytype.
    element entryfields {
      element entrytype { text }*,
      element field { text }+
    }+,
    # Allowable multiscript fields which can have alternate form/languages
    element multiscriptfields {
      element field { text }+
    },
    # Constraints on field (co-)existence and format
    element constraints {
      # Set of entrytypes that this constraint applies to
      # An entrytype can be specified in multiple constraints
      #
      element entrytype { text }*,
      # A constraint specification
      element constraint {
        (
          # Conditional constraints have an antecedent and consequent
          # both of which have a quantifier. This allows you to enforce
          # constraints like:
          #
          # if field a,b,c are all present then one of x,y,z must be
          # if one of field a,b,c are present then none of x,y,z must be
          # etc.
          (attribute type { "conditional" },
            element antecedent {
              attribute quant { "all" | "one" | "none"},
              element field { text }+
            },
            element consequent {
              attribute quant { "all" | "one" | "none"},
              element field { text }+
            }
          ) |
          # Datatype and format constraints
          (attribute type { "data" },
            # range* attributes are for limiting integer type range
            attribute datatype { "integer" | "isbn" | "issn" | "ismn" | "date" | "pattern" }?,
            attribute rangemin { xsd:int }?,
            attribute rangemax { xsd:int }?,
            attribute pattern { text }?,
            element field { text }+
          ) |
          # Mandatoriness constraints which say which fields must appear
          (attribute type { "mandatory" },
            (element field { text } |
              # An XOR set of fields so you can enforce:
              #
              # One (but not more) of fields a,b,c must exist
              element fieldxor {
                element field { text }+
              } |
              # An OR set of fields so you can enforce:
              #
              # One (possibly more) of fields a,b,c must exist
              element fieldor {
                element field { text }+
              }
            )+
          )
        )
      }*
    }+
  }

translit =
  element transliteration {
    attribute entrytype { "*" | xsd:string {minLength="1"} },
    element translit {
      attribute target { "*" | xsd:string {minLength="1"} },
      attribute from { xsd:string {minLength="1"} },
      attribute to { xsd:string {minLength="1"} }
    }+
  }

inheritance =
  # Cross-reference inheritance specifications
element inheritance {
  # Defaults
  element defaults {
    # Whether to inherit all fields
    attribute inherit_all { "true" | "false" },
    # Should we overwrite the target field if it exists?
    attribute override_target { "true" | "false" },
    # ignore of uniqueness tracking
    attribute ignore { text }?,
    # Default inherit_all and override_target settings for entrytype source/target pairs
    element type_pair {
      attribute source { "*" | xsd:string {minLength="1"}},
      attribute target { "*" | xsd:string {minLength="1"}},
      attribute inherit_all { "true" | "false" }?,
      attribute override_target { "true" | "false" }?,
      attribute ignore { text }?,
      empty
    }*
  },
  # An inheritance specification
  element inherit {
    # ignore of uniqueness tracking
    attribute ignore { text }?,
    # applies to these pairs of source/target entrytypes
    element type_pair {
      attribute source { "*" | xsd:string {minLength="1"}},
      attribute target { "*" | xsd:string {minLength="1"}},
      empty
    }+,
    # and here are the field specifications
    element field {
      (
        # either a "skip this field" specification
        # so we can say inherit all except certain fields OR ...
        (attribute source { xsd:string },
          attribute skip { "true" | "false" }) |
        # ... a source and target field with an optional override attribute
        (attribute source { xsd:string {minLength="1"}},
          attribute target { xsd:string {minLength="1"}},
          attribute override_target { "true" | "false" }?)
      ),
      empty
    }+
  }*
}

map =
  element map {
    attribute map_overwrite { "0" | "1" }?,
    attribute map_foreach { xsd:string {minLength="1"} }?,
    attribute refsection { xsd:integer }?,
    element per_datasource { xsd:string {minLength="1"} }*,
    element per_type { xsd:string {minLength="1"} }*,
    element map_step {
      (
        ( attribute map_entry_clone { xsd:string {minLength="1"} }
        ) |
        ( attribute map_entry_new { xsd:string {minLength="1"} },
          attribute map_entry_newtype { xsd:string {minLength="1"} }
        ) |
        ( attribute map_entrykey_cited { "1" }?,
          attribute map_entrykey_nocited { "1" }?,
          attribute map_entrykey_citedornocited { "1" }?,
          attribute map_entrykey_allnocited { "1" }?,
          attribute map_entrykey_starnocited { "1" }?,
          attribute map_type_source { xsd:string {minLength="1"} }?,
          attribute map_type_target { xsd:string {minLength="1"} }?,
          attribute map_field_source { xsd:string {minLength="1"} }?,
          attribute map_notfield { xsd:string {minLength="1"} }?,
          attribute map_field_target { xsd:string {minLength="1"} }?,
          attribute map_entrytarget { xsd:string {minLength="1"} }?,
          attribute map_field_set { xsd:string {minLength="1"} }?,
          attribute map_entry_null { "1" }?,
          attribute map_append { "1" }?,
          attribute map_appendstrict { "1" }?,
          attribute map_final { "1" }?,
          attribute map_match { xsd:string {minLength="1"} }?,
          attribute map_matchi { xsd:string {minLength="1"} }?,
          attribute map_notmatch { xsd:string {minLength="1"} }?,
          attribute map_notmatchi { xsd:string {minLength="1"} }?,
          attribute map_replace { xsd:string }?,
          ( attribute map_null { "1" } |
            attribute map_origfield { "1" } |
            attribute map_origfieldval { "1" } |
            attribute map_origentrytype { "1" } |
            attribute map_field_value { xsd:string {minLength="1"} } )?
        )
      ),
      empty
    }+
  }


labelalphanametemplate =     
    element labelalphanametemplate {
      attribute name { xsd:string }?,
      element namepart {
        attribute order { xsd:integer },
        attribute use { "0" | "1" }?,
        attribute pre { "0" | "1" }?,
        attribute substring_width { xsd:integer }?,
        attribute substring_compound { "0" | "1" }?,
        attribute substring_side { "left" | "right" }?,
        text
      }+
    }
    
labelalphatemplate =         
    element labelalphatemplate {
      attribute type { xsd:string }?, # per-type?
      element labelelement {
        attribute order { xsd:integer },
        element labelpart {          
          attribute final { "0" | "1" }?,
          attribute pad_char { xsd:string {minLength="1"}}?,
          attribute pad_side { "left" | "right" }?,
          attribute substring_width { xsd:integer | "v" | "vf" | "l" }?,
          attribute substring_fixed_threshold { xsd:integer }?,
          attribute substring_width_max { xsd:integer }?,
          attribute substring_side { "left" | "right" }?,
          attribute ifnames { text }?,
          attribute names { text }?,
          attribute namessep { string }?,
          attribute noalphaothers { "0" | "1" }?,
          xsd:string
        }+
      }+
    }


uniquenametemplate = 
  element uniquenametemplate {
    attribute name { xsd:string {minLength="1"} },
    element namepart {
     attribute order { xsd:integer },
      attribute use { "0" | "1" }?,
      attribute base { "0" | "1" }?,
      attribute context { "none" | "init" | "initorfull" | "full" }?,
      text
    }+
  }

sortingnamekeytemplate = 
  element sortingnamekeytemplate {
    attribute name { text },
    element keypart {
      attribute order { xsd:integer },
      element part {
        attribute type { "namepart" | "literal" },
        attribute order { xsd:integer },
        attribute use { "0" | "1" }?,
        attribute inits { "0" | "1" }?,
        text
      }+
    }+
  }

sortingtemplate = 
  element sortingtemplate {
    # sorting template name
    attribute name { xsd:string {minLength="1"}},
    # locale for entire sorting specification
    attribute locale { xsd:string {minLength="1"}}?,
    sort+
  }

sort =
  # sort specification
element sort {
  # order of this specification in the set of all sort specifications
  attribute order { xsd:integer },
  # Should we stop generating sorting information after this item?
  attribute final { "1" }?,
  # Sort ascending or descending
  attribute sort_direction { "ascending" | "descending" }?,
  # Sort case sensitive or not?
  attribute sortcase { "0" | "1" }?,
  # Sort upper before lower?
  attribute sortupper { "0" | "1" }?,
  # sortset specific override for locale
  attribute locale { xsd:string {minLength="1"}}?,
  # A sort item specification - a field or pseudo-field to get sort information from
  element sortitem {
    # order of this item in the set of all other item specifications
    attribute order { xsd:integer },
    # Just use a part of the item information for sorting?
    attribute substring_side { "left" | "right" }?,
    attribute substring_width { xsd:integer }?,
    # Pad the item information when sorting with it?
    attribute pad_side { "left" | "right" }?,
    attribute pad_width { xsd:integer }?,
    attribute pad_char { xsd:string { minLength = "1" maxLength = "1" } }?,
    attribute form { "original" | "translated" | "romanised" | "uniform" }?,
    text
  }+
}+

dmfieldtype =  "field" | "list"
dmdatatype =  "literal" | "name" | "key" | "entrykey" | "date" | "verbatim" | "integer" | "range" | "code" | "uri" | "datepart" | "keyword" | "option"

# Copyright 2012-2020 Philip Kime, all rights reserved.

# This code is free software.  You can redistribute it and/or
# modify it under the terms of the Artistic License 2.0.

# 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.
