<?xml version="1.0" encoding="UTF-8"?>
<!--
  CheeseXML 1.00 — interchange schema for cheese recipes.

  Analogous to BeerXML: a record-set document that can hold one or many
  recipes, with strictly typed quantities, controlled vocabularies, and
  ordered process steps. Unlike BeerXML 1.0, CheeseXML is designed for
  multilingual software from the start:

    * Human-readable strings live in <T xml:lang="…"> children (BCP 47).
    * Optional @dir (ltr|rtl|auto) positions text for the language's script.
    * Categorical meaning lives in machine codes (family, phase, species…).
    * UI software resolves codes via vocabularies.xml, so labels can be
      shown in any language without rewriting recipes.
    * Units are always explicit attributes; never implied by element name.

  Namespace: https://www.samovar-tool.ru/cheesexml/ns/1.0
  Spec:      /cheesexml/SPEC.md
  Vocab:     /cheesexml/vocabularies.xml
-->
<xs:schema
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:xml="http://www.w3.org/XML/1998/namespace"
  xmlns:cx="https://www.samovar-tool.ru/cheesexml/ns/1.0"
  targetNamespace="https://www.samovar-tool.ru/cheesexml/ns/1.0"
  elementFormDefault="qualified"
  attributeFormDefault="unqualified"
  version="1.00">

  <xs:import namespace="http://www.w3.org/XML/1998/namespace"
             schemaLocation="xml.xsd"/>

  <xs:annotation>
    <xs:documentation xml:lang="en">
      CheeseXML 1.00. Root document may contain any number of RECIPE records.
      Individual files in this distribution contain one RECIPE each, but a
      compliant document MAY bundle many recipes in a single RECIPES set.
      Readers MUST inspect CHEESEXML/@version before parsing.
    </xs:documentation>
    <xs:documentation xml:lang="ru">
      CheeseXML 1.00. Корневой документ может содержать любое число записей
      RECIPE. Файлы этой поставки содержат по одному рецепту, но корректный
      документ МОЖЕТ объединять много рецептов в одном наборе RECIPES.
      Читатель ОБЯЗАН сначала прочитать CHEESEXML/@version.
    </xs:documentation>
  </xs:annotation>

  <!-- ============================================================ -->
  <!-- Primitive / reusable types                                    -->
  <!-- ============================================================ -->

  <xs:simpleType name="SchemaVersion">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        CheeseXML schema version as major.minor with two-digit minor
        (1.00, 1.01, 2.00). Software MUST read CHEESEXML/@version first
        to select a parser. Same major = backward compatible; a newer
        minor may add optional elements that older readers MUST ignore.
        A different major is a breaking change.
      </xs:documentation>
      <xs:documentation xml:lang="ru">
        Версия схемы CheeseXML в виде major.minor с двузначным minor
        (1.00, 1.01, 2.00). Программа ОБЯЗАНА сначала прочитать
        CHEESEXML/@version и выбрать парсер. Один major — обратная
        совместимость; более новый minor может добавить необязательные
        элементы, которые старые читатели ОБЯЗАНЫ игнорировать.
        Другой major — несовместимое изменение.
      </xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:token">
      <xs:pattern value="[0-9]+\.[0-9]{2}"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="Code">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        Language-independent token. Dotted hierarchical codes are preferred
        (family.style, genus.species, phase.action). UI MUST NOT display the
        raw code to end users; resolve via VOCABULARIES.
      </xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:token">
      <xs:minLength value="1"/>
      <xs:pattern value="[A-Za-z][A-Za-z0-9_]*(\.[A-Za-z][A-Za-z0-9_]*)*"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="Id">
    <xs:restriction base="xs:token">
      <xs:minLength value="1"/>
      <xs:pattern value="[a-z][a-z0-9_\-]*"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="CountryCode">
    <xs:annotation>
      <xs:documentation>ISO 3166-1 alpha-2, uppercase.</xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:token">
      <xs:pattern value="[A-Z]{2}"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="LangCode">
    <xs:annotation>
      <xs:documentation>BCP 47 language tag (en, ru, fr, pt-BR…).</xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:language"/>
  </xs:simpleType>

  <xs:simpleType name="TextDir">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        Writing direction used to position this string in the UI
        (CSS direction). Independent of xml:lang so a mixed-script
        translation can override the language's default.
      </xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:token">
      <xs:enumeration value="ltr"/>
      <xs:enumeration value="rtl"/>
      <xs:enumeration value="auto"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="UnitCode">
    <xs:restriction base="xs:token">
      <xs:enumeration value="C"/>
      <xs:enumeration value="F"/>
      <xs:enumeration value="K"/>
      <xs:enumeration value="s"/>
      <xs:enumeration value="min"/>
      <xs:enumeration value="h"/>
      <xs:enumeration value="d"/>
      <xs:enumeration value="week"/>
      <xs:enumeration value="month"/>
      <xs:enumeration value="year"/>
      <xs:enumeration value="g"/>
      <xs:enumeration value="kg"/>
      <xs:enumeration value="mg"/>
      <xs:enumeration value="lb"/>
      <xs:enumeration value="oz"/>
      <xs:enumeration value="ml"/>
      <xs:enumeration value="l"/>
      <xs:enumeration value="gal"/>
      <xs:enumeration value="gal_uk"/>
      <xs:enumeration value="qt"/>
      <xs:enumeration value="pint"/>
      <xs:enumeration value="cup"/>
      <xs:enumeration value="tsp"/>
      <xs:enumeration value="tbsp"/>
      <xs:enumeration value="fl_oz"/>
      <xs:enumeration value="mm"/>
      <xs:enumeration value="cm"/>
      <xs:enumeration value="in"/>
      <xs:enumeration value="kPa"/>
      <xs:enumeration value="psi"/>
      <xs:enumeration value="percent"/>
      <xs:enumeration value="ppm"/>
      <xs:enumeration value="IMCU"/>
      <xs:enumeration value="MCU"/>
      <xs:enumeration value="SU"/>
      <xs:enumeration value="U"/>
      <xs:enumeration value="drops"/>
      <xs:enumeration value="item"/>
      <xs:enumeration value="ratio"/>
      <xs:enumeration value="EA"/>
      <xs:enumeration value="DCU"/>
      <xs:enumeration value="CXU"/>
      <xs:enumeration value="T"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="UnitSystem">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        Kitchen-unit convention of a document or recipe. Codes themselves
        are never overloaded except cup/tsp/tbsp (metric kitchen vs US)
        and gal (US vs imperial when system="imperial" and the code is gal
        rather than gal_uk). Software MUST still read Quantity/@unit and
        SHOULD prefer Quantity/@si as the interchange pivot.
      </xs:documentation>
      <xs:documentation xml:lang="ru">
        Кухонная система мер документа или рецепта. Коды единиц однозначны,
        кроме cup/tsp/tbsp (метрическая чашка 250 мл против US) и gal
        (US против имперского, если system="imperial" и код gal, а не gal_uk).
        Программа ОБЯЗАНА читать Quantity/@unit и ДОЛЖНА предпочитать
        Quantity/@si как точку обмена.
      </xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:token">
      <xs:enumeration value="metric"/>
      <xs:enumeration value="us"/>
      <xs:enumeration value="imperial"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="FamilyCode">
    <xs:restriction base="xs:token">
      <xs:enumeration value="fresh"/>
      <xs:enumeration value="whey"/>
      <xs:enumeration value="acid_set"/>
      <xs:enumeration value="pasta_filata"/>
      <xs:enumeration value="brined"/>
      <xs:enumeration value="soft_ripened"/>
      <xs:enumeration value="washed_rind"/>
      <xs:enumeration value="semi_hard"/>
      <xs:enumeration value="hard"/>
      <xs:enumeration value="blue"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="SpeciesCode">
    <xs:restriction base="xs:token">
      <xs:enumeration value="bos_taurus"/>
      <xs:enumeration value="capra_hircus"/>
      <xs:enumeration value="ovis_aries"/>
      <xs:enumeration value="bubalus_bubalis"/>
      <xs:enumeration value="mixed"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="MilkTreatment">
    <xs:restriction base="xs:token">
      <xs:enumeration value="raw"/>
      <xs:enumeration value="thermized"/>
      <xs:enumeration value="pasteurized"/>
      <xs:enumeration value="boiled"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="Homogenization">
    <xs:restriction base="xs:token">
      <xs:enumeration value="none"/>
      <xs:enumeration value="partial"/>
      <xs:enumeration value="full"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="IngredientRole">
    <xs:restriction base="xs:token">
      <xs:enumeration value="base"/>
      <xs:enumeration value="cream"/>
      <xs:enumeration value="whey"/>
      <xs:enumeration value="culture"/>
      <xs:enumeration value="coagulant"/>
      <xs:enumeration value="acid"/>
      <xs:enumeration value="mineral"/>
      <xs:enumeration value="enzyme"/>
      <xs:enumeration value="mold"/>
      <xs:enumeration value="smear"/>
      <xs:enumeration value="salt"/>
      <xs:enumeration value="water"/>
      <xs:enumeration value="spice"/>
      <xs:enumeration value="ash"/>
      <xs:enumeration value="adjunct"/>
      <xs:enumeration value="other"/>
      <xs:enumeration value="protective"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="PhaseCode">
    <xs:restriction base="xs:token">
      <xs:enumeration value="milk_prep"/>
      <xs:enumeration value="calcium_correction"/>
      <xs:enumeration value="ripening"/>
      <xs:enumeration value="coagulation"/>
      <xs:enumeration value="cutting"/>
      <xs:enumeration value="healing"/>
      <xs:enumeration value="stirring"/>
      <xs:enumeration value="cooking"/>
      <xs:enumeration value="washing"/>
      <xs:enumeration value="draining"/>
      <xs:enumeration value="knitting"/>
      <xs:enumeration value="cheddaring"/>
      <xs:enumeration value="milling"/>
      <xs:enumeration value="stretching"/>
      <xs:enumeration value="molding"/>
      <xs:enumeration value="pressing"/>
      <xs:enumeration value="salting"/>
      <xs:enumeration value="drying"/>
      <xs:enumeration value="piercing"/>
      <xs:enumeration value="rind_treatment"/>
      <xs:enumeration value="aging"/>
      <xs:enumeration value="packaging"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="RecipeKind">
    <xs:restriction base="xs:token">
      <xs:enumeration value="traditional"/>
      <xs:enumeration value="home"/>
      <xs:enumeration value="industrial_adapted"/>
      <xs:enumeration value="experimental"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="Difficulty">
    <xs:restriction base="xs:integer">
      <xs:minInclusive value="1"/>
      <xs:maxInclusive value="5"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="AmountBasis">
    <xs:restriction base="xs:token">
      <xs:enumeration value="batch"/>
      <xs:enumeration value="per_l"/>
      <xs:enumeration value="per_kg_milk"/>
      <xs:enumeration value="per_kg_curd"/>
      <xs:enumeration value="to_taste"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="RelationKind">
    <xs:restriction base="xs:token">
      <xs:enumeration value="variant"/>
      <xs:enumeration value="parent"/>
      <xs:enumeration value="child"/>
      <xs:enumeration value="whey_byproduct"/>
      <xs:enumeration value="accompanies"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- Localized text: one or more <T xml:lang> children. Software picks
       the best language, then @primary, then the first child.
       @dir positions the string for LTR/RTL scripts. -->
  <xs:complexType name="LocalizedText">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        Multilingual string. Each T carries xml:lang (BCP 47) and optional
        dir (ltr|rtl|auto) for layout positioning. Optional primary="true"
        marks the author's preferred language. UIs MUST select by requested
        language (exact, then prefix), then primary, then document order,
        and MUST apply @dir to the rendered run of text.
      </xs:documentation>
      <xs:documentation xml:lang="ru">
        Многоязычная строка. Каждый T несёт xml:lang (BCP 47) и необязательный
        dir (ltr|rtl|auto) для позиционирования в интерфейсе. Атрибут
        primary="true" отмечает язык автора. Интерфейс обязан выбрать
        запрошенный язык (точное совпадение, затем префикс), затем primary,
        затем первый элемент, и применить @dir к отрисованному тексту.
      </xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="T" maxOccurs="unbounded">
        <xs:complexType>
          <xs:simpleContent>
            <xs:extension base="xs:string">
              <xs:attribute ref="xml:lang" use="required"/>
              <xs:attribute name="dir" type="cx:TextDir" use="optional" default="ltr"/>
              <xs:attribute name="primary" type="xs:boolean" use="optional"/>
            </xs:extension>
          </xs:simpleContent>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="Quantity">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        Scalar measurement. @value is the numeric magnitude in @unit.
        Optional @si is the same magnitude in the canonical SI unit of
        that dimension (litre, gram, degree Celsius, millimetre, kilopascal)
        and is the interchange pivot: a reader that does not know a kitchen
        unit still converts. Optional @min/@max are in the same unit as
        @value. Do not encode the unit in the element name.
      </xs:documentation>
      <xs:documentation xml:lang="ru">
        Скаляр. @value — число в единицах @unit. Необязательный @si —
        та же величина в канонической СИ-единице измерения (литр, грамм,
        градус Цельсия, миллиметр, килопаскаль) и точка обмена: читатель,
        который не знает кухонную единицу, всё равно пересчитает.
        @min/@max — в тех же единицах, что @value. Единицу нельзя зашивать
        в имя элемента.
      </xs:documentation>
    </xs:annotation>
    <xs:attribute name="value" type="xs:decimal" use="required"/>
    <xs:attribute name="unit" type="cx:UnitCode" use="required"/>
    <xs:attribute name="min" type="xs:decimal" use="optional"/>
    <xs:attribute name="max" type="xs:decimal" use="optional"/>
    <xs:attribute name="si" type="xs:decimal" use="optional"/>
  </xs:complexType>

  <xs:complexType name="PhType">
    <xs:attribute name="value" type="xs:decimal" use="required"/>
    <xs:attribute name="min" type="xs:decimal" use="optional"/>
    <xs:attribute name="max" type="xs:decimal" use="optional"/>
  </xs:complexType>

  <xs:complexType name="CodedTerm">
    <xs:attribute name="code" type="cx:Code" use="required"/>
  </xs:complexType>

  <!-- ============================================================ -->
  <!-- Root                                                          -->
  <!-- ============================================================ -->

  <xs:element name="CHEESEXML">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="RECIPES" type="cx:RecipesType"/>
      </xs:sequence>
      <xs:attribute name="version" type="cx:SchemaVersion" use="required"/>
      <xs:attribute name="generator" type="xs:string" use="optional"/>
      <xs:attribute name="defaultLang" type="cx:LangCode" use="optional"/>
      <xs:attribute name="units" type="cx:UnitSystem" use="optional"/>
      <xs:attribute ref="xml:lang" use="optional"/>
    </xs:complexType>
    <xs:unique name="UniqueRecipeId">
      <xs:selector xpath="cx:RECIPES/cx:RECIPE"/>
      <xs:field xpath="@id"/>
    </xs:unique>
  </xs:element>

  <xs:complexType name="RecipesType">
    <xs:sequence>
      <xs:element name="RECIPE" type="cx:RecipeType" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

  <!-- ============================================================ -->
  <!-- Recipe                                                        -->
  <!-- ============================================================ -->

  <xs:complexType name="RecipeType">
    <xs:sequence>
      <xs:element name="META" type="cx:MetaType"/>
      <xs:element name="NAME" type="cx:LocalizedText"/>
      <xs:element name="AKA" type="cx:LocalizedText" minOccurs="0" maxOccurs="unbounded"/>
      <xs:element name="DESCRIPTION" type="cx:LocalizedText"/>
      <xs:element name="ORIGIN" type="cx:OriginType" minOccurs="0"/>
      <xs:element name="STYLE" type="cx:StyleType"/>
      <xs:element name="BATCH" type="cx:BatchType"/>
      <xs:element name="MILK" type="cx:MilkType"/>
      <xs:element name="INGREDIENTS" type="cx:IngredientsType"/>
      <xs:element name="EQUIPMENT" type="cx:EquipmentType" minOccurs="0"/>
      <xs:element name="PROCESS" type="cx:ProcessType"/>
      <xs:element name="WHEY" type="cx:WheyType" minOccurs="0"/>
      <xs:element name="TARGETS" type="cx:TargetsType" minOccurs="0"/>
      <xs:element name="AGING" type="cx:AgingType" minOccurs="0"/>
      <xs:element name="SENSORY" type="cx:SensoryType" minOccurs="0"/>
      <xs:element name="STORAGE" type="cx:StorageType" minOccurs="0"/>
      <xs:element name="PACKAGING" type="cx:PackagingType" minOccurs="0"/>
      <xs:element name="ALLERGENS" type="cx:AllergensType" minOccurs="0"/>
      <xs:element name="SAFETY" type="cx:LocalizedText" minOccurs="0"/>
      <xs:element name="SOURCE" type="cx:SourceType" minOccurs="0" maxOccurs="unbounded"/>
      <xs:element name="RELATED" type="cx:RelatedType" minOccurs="0" maxOccurs="unbounded"/>
      <xs:element name="TAGS" type="cx:TagsType" minOccurs="0"/>
      <xs:element name="NOTES" type="cx:LocalizedText" minOccurs="0"/>
      <xs:element name="EXTENSION" type="cx:ExtensionType" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="id" type="cx:Id" use="required"/>
    <xs:attribute name="version" type="xs:positiveInteger" use="optional" default="1"/>
  </xs:complexType>

  <xs:complexType name="MetaType">
    <xs:sequence>
      <xs:element name="SCHEMA_VERSION" type="cx:SchemaVersion"/>
      <xs:element name="TYPE" type="cx:RecipeKind"/>
      <xs:element name="DIFFICULTY" type="cx:Difficulty"/>
      <xs:element name="VEGETARIAN" type="xs:boolean" minOccurs="0"/>
      <xs:element name="CREATED" type="xs:date" minOccurs="0"/>
      <xs:element name="UPDATED" type="xs:date" minOccurs="0"/>
      <xs:element name="LICENSE" type="xs:token" minOccurs="0"/>
      <xs:element name="AUTHOR" type="cx:LocalizedText" minOccurs="0"/>
      <xs:element name="UNITS" minOccurs="0">
        <xs:annotation>
          <xs:documentation xml:lang="en">
            Per-recipe kitchen-unit convention. Overrides CHEESEXML/@units
            for this record. Readers that do not understand UNITS ignore it
            and still convert via Quantity/@unit and @si.
          </xs:documentation>
          <xs:documentation xml:lang="ru">
            Кухонная система мер этого рецепта. Перекрывает CHEESEXML/@units.
            Старый читатель игнорирует элемент и пересчитывает по @unit/@si.
          </xs:documentation>
        </xs:annotation>
        <xs:complexType>
          <xs:attribute name="system" type="cx:UnitSystem" use="required"/>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="OriginType">
    <xs:sequence>
      <xs:element name="COUNTRY" type="cx:CountryCode"/>
      <xs:element name="REGION" type="cx:LocalizedText" minOccurs="0"/>
      <xs:element name="PDO" type="xs:boolean" minOccurs="0"/>
      <xs:element name="PDO_NAME" type="cx:LocalizedText" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="StyleType">
    <xs:attribute name="family" type="cx:FamilyCode" use="required"/>
    <xs:attribute name="code" type="cx:Code" use="required"/>
  </xs:complexType>

  <xs:complexType name="BatchType">
    <xs:sequence>
      <xs:element name="MILK_VOLUME" type="cx:Quantity"/>
      <xs:element name="EXPECTED_YIELD" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="YIELD_RATIO" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="ACTIVE_TIME" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="TOTAL_TIME" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="HOOP" minOccurs="0">
        <xs:complexType>
          <xs:complexContent>
            <xs:extension base="cx:Quantity">
              <xs:attribute name="shape" type="cx:Code" use="optional"/>
            </xs:extension>
          </xs:complexContent>
        </xs:complexType>
      </xs:element>
      <xs:element name="SCALE">
        <xs:complexType>
          <xs:attribute name="base" type="xs:token" use="required"/>
          <xs:attribute name="base_value" type="xs:decimal" use="required"/>
          <xs:attribute name="base_unit" type="cx:UnitCode" use="required"/>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="MilkType">
    <xs:sequence>
      <xs:element name="BLEND" type="cx:BlendType" minOccurs="0"/>
      <xs:element name="FAT" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="PROTEIN" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="PH" type="cx:PhType" minOccurs="0"/>
      <!-- Optional 1.00: Turner acidity (°T) and fat/protein ratio. -->
      <xs:element name="ACIDITY" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="FAT_PROTEIN_RATIO" type="cx:Quantity" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="species" type="cx:SpeciesCode" use="required"/>
    <xs:attribute name="breed" type="xs:token" use="optional"/>
    <xs:attribute name="treatment" type="cx:MilkTreatment" use="required"/>
    <xs:attribute name="homogenization" type="cx:Homogenization" use="required"/>
  </xs:complexType>

  <xs:complexType name="BlendType">
    <xs:sequence>
      <xs:element name="PART" maxOccurs="unbounded">
        <xs:complexType>
          <xs:attribute name="species" type="cx:SpeciesCode" use="required"/>
          <xs:attribute name="percent" type="xs:decimal" use="required"/>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="IngredientsType">
    <xs:sequence>
      <xs:element name="INGREDIENT" type="cx:IngredientType" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="IngredientType">
    <xs:sequence>
      <xs:element name="NAME" type="cx:LocalizedText"/>
      <xs:element name="AMOUNT" type="cx:AmountType"/>
      <xs:element name="DETAIL" type="cx:IngredientDetailType" minOccurs="0"/>
      <xs:element name="PREP" type="cx:PrepType" minOccurs="0"/>
      <xs:element name="SUBSTITUTE" type="cx:SubstituteType" minOccurs="0" maxOccurs="unbounded"/>
      <xs:element name="NOTES" type="cx:LocalizedText" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="id" type="cx:Id" use="required"/>
    <xs:attribute name="role" type="cx:IngredientRole" use="required"/>
    <xs:attribute name="kind" type="cx:Code" use="optional"/>
    <xs:attribute name="optional" type="xs:boolean" use="optional" default="false"/>
    <xs:attribute name="added_in_step" type="xs:positiveInteger" use="optional"/>
  </xs:complexType>

  <xs:complexType name="AmountType">
    <xs:complexContent>
      <xs:extension base="cx:Quantity">
        <xs:attribute name="basis" type="cx:AmountBasis" use="optional" default="batch"/>
      </xs:extension>
    </xs:complexContent>
  </xs:complexType>

  <xs:complexType name="PrepType">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        How the ingredient is prepared before it enters the vat: typically
        dilution in non-chlorinated water, a brief hydration rest, or both.
      </xs:documentation>
      <xs:documentation xml:lang="ru">
        Как ингредиент готовят до внесения в ванну: обычно разведение в
        нехлорированной воде и/или короткая гидратация.
      </xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="DILUTE_IN" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="TIME" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="INSTRUCTION" type="cx:LocalizedText" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="SubstituteType">
    <xs:sequence>
      <xs:element name="NAME" type="cx:LocalizedText"/>
      <xs:element name="AMOUNT" type="cx:AmountType" minOccurs="0"/>
      <xs:element name="NOTES" type="cx:LocalizedText" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="kind" type="cx:Code" use="optional"/>
  </xs:complexType>

  <xs:complexType name="IngredientDetailType">
    <xs:choice>
      <xs:element name="CULTURE">
        <xs:complexType>
          <xs:attribute name="code" type="cx:Code" use="required"/>
          <xs:attribute name="form" type="xs:token" use="optional"/>
          <xs:attribute name="species" type="xs:token" use="optional"/>
          <xs:attribute name="dcu" type="xs:decimal" use="optional"/>
          <xs:attribute name="dose_fraction" type="xs:decimal" use="optional"/>
          <xs:attribute name="bulk_pct" type="xs:decimal" use="optional"/>
        </xs:complexType>
      </xs:element>
      <xs:element name="COAGULANT">
        <xs:complexType>
          <xs:attribute name="code" type="cx:Code" use="required"/>
          <xs:attribute name="strength" type="xs:token" use="optional"/>
          <xs:attribute name="imcu" type="xs:decimal" use="optional"/>
          <xs:attribute name="chymosin_pct" type="xs:decimal" use="optional"/>
          <xs:attribute name="pepsin_pct" type="xs:decimal" use="optional"/>
        </xs:complexType>
      </xs:element>
      <xs:element name="ACID">
        <xs:complexType>
          <xs:attribute name="code" type="cx:Code" use="required"/>
          <xs:attribute name="strength_percent" type="xs:decimal" use="optional"/>
        </xs:complexType>
      </xs:element>
      <xs:element name="MINERAL">
        <xs:complexType>
          <xs:attribute name="code" type="cx:Code" use="required"/>
          <xs:attribute name="solution_percent" type="xs:decimal" use="optional"/>
        </xs:complexType>
      </xs:element>
      <xs:element name="ENZYME">
        <xs:complexType>
          <xs:attribute name="code" type="cx:Code" use="required"/>
        </xs:complexType>
      </xs:element>
      <xs:element name="SALT">
        <xs:complexType>
          <xs:attribute name="method" type="xs:token" use="optional"/>
          <xs:attribute name="iodized" type="xs:boolean" use="optional"/>
        </xs:complexType>
      </xs:element>
      <xs:element name="MOLD">
        <xs:complexType>
          <xs:attribute name="code" type="cx:Code" use="required"/>
          <xs:attribute name="species" type="xs:token" use="optional"/>
        </xs:complexType>
      </xs:element>
      <xs:element name="SMEAR">
        <xs:complexType>
          <xs:attribute name="code" type="cx:Code" use="required"/>
          <xs:attribute name="species" type="xs:token" use="optional"/>
        </xs:complexType>
      </xs:element>
    </xs:choice>
  </xs:complexType>

  <xs:complexType name="EquipmentType">
    <xs:sequence>
      <xs:element name="ITEM" maxOccurs="unbounded">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="NAME" type="cx:LocalizedText"/>
            <xs:element name="NOTES" type="cx:LocalizedText" minOccurs="0"/>
          </xs:sequence>
          <xs:attribute name="code" type="cx:Code" use="required"/>
          <xs:attribute name="optional" type="xs:boolean" use="optional" default="false"/>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="ProcessType">
    <xs:sequence>
      <xs:element name="STEP" type="cx:StepType" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="StepType">
    <xs:sequence>
      <xs:element name="NAME" type="cx:LocalizedText"/>
      <xs:element name="INSTRUCTION" type="cx:LocalizedText"/>
      <xs:element name="PARAMS" type="cx:ParamsType" minOccurs="0"/>
      <xs:element name="NOTES" type="cx:LocalizedText" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="n" type="xs:positiveInteger" use="required"/>
    <xs:attribute name="phase" type="cx:PhaseCode" use="required"/>
    <xs:attribute name="code" type="cx:Code" use="required"/>
    <xs:attribute name="optional" type="xs:boolean" use="optional" default="false"/>
  </xs:complexType>

  <xs:complexType name="ParamsType">
    <xs:sequence>
      <xs:element name="TEMP" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="TIME" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="PH" type="cx:PhType" minOccurs="0"/>
      <xs:element name="HUMIDITY" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="SIZE" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="FLOC" minOccurs="0">
        <xs:complexType>
          <xs:attribute name="time" type="xs:decimal" use="required"/>
          <xs:attribute name="unit" type="cx:UnitCode" use="required"/>
          <xs:attribute name="multiplier" type="xs:decimal" use="required"/>
        </xs:complexType>
      </xs:element>
      <xs:element name="PRESS" minOccurs="0">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="STAGE" minOccurs="0" maxOccurs="unbounded">
              <xs:complexType>
                <xs:sequence>
                  <xs:element name="MASS" type="cx:Quantity" minOccurs="0"/>
                  <xs:element name="DURATION" type="cx:Quantity" minOccurs="0"/>
                </xs:sequence>
                <xs:attribute name="n" type="xs:positiveInteger" use="required"/>
              </xs:complexType>
            </xs:element>
            <xs:element name="MASS" type="cx:Quantity" minOccurs="0"/>
            <xs:element name="DURATION" type="cx:Quantity" minOccurs="0"/>
            <xs:element name="PRESSURE" type="cx:Quantity" minOccurs="0"/>
            <xs:element name="HOOP_DIAMETER" type="cx:Quantity" minOccurs="0"/>
          </xs:sequence>
          <xs:attribute name="method" type="xs:token" use="optional"/>
        </xs:complexType>
      </xs:element>
      <xs:element name="TARGET" type="cx:CodedTerm" minOccurs="0" maxOccurs="unbounded"/>
      <!-- Optional fields added in 1.00 after cataloguing published home recipes.
           Old 1.00 readers MUST ignore unknown children (forward compatible). -->
      <xs:element name="WHEY_DRAW" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="WASH_WATER" type="cx:WashWaterType" minOccurs="0"/>
      <xs:element name="BRINE" type="cx:BrineType" minOccurs="0"/>
      <xs:element name="FLIP" minOccurs="0">
        <xs:complexType>
          <xs:attribute name="every" type="xs:decimal" use="required"/>
          <xs:attribute name="unit" type="cx:UnitCode" use="required"/>
        </xs:complexType>
      </xs:element>
      <!-- Optional process params added in 1.00 after comparing published
           home recipes. They stay optional: version remains 1.00.
           Older 1.00 readers MUST ignore unknown children. -->
      <xs:element name="RAMP" type="cx:RampType" minOccurs="0"/>
      <xs:element name="HOLD" type="cx:HoldType" minOccurs="0"/>
      <xs:element name="COOL" type="cx:CoolType" minOccurs="0"/>
      <xs:element name="RATE" type="cx:RateType" minOccurs="0"/>
      <xs:element name="STIR" type="cx:StirType" minOccurs="0"/>
      <xs:element name="CUT" type="cx:CutType" minOccurs="0"/>
      <xs:element name="UNTIL" type="cx:UntilType" minOccurs="0"/>
      <xs:element name="DRAIN" type="cx:DrainType" minOccurs="0"/>
      <xs:element name="STRETCH_WATER" type="cx:WashWaterType" minOccurs="0"/>
      <!-- Optional BeerXML-style typed vat operations (1.00, all optional).
           A plant tech sheet (pasteurize / cool / culture / CaCl2 / floc /
           H+V cut / settle / cook rate / hoop flips / stufatura) is stored
           as these children, not as prose. Older 1.00 readers ignore them. -->
      <xs:element name="ADDITION" type="cx:VatAdditionType" minOccurs="0" maxOccurs="unbounded"/>
      <xs:element name="CUTS" type="cx:CutsType" minOccurs="0"/>
      <xs:element name="SETTLE" type="cx:SettleType" minOccurs="0"/>
      <xs:element name="FLIPS" type="cx:FlipsType" minOccurs="0"/>
      <xs:element name="STUFATURA" type="cx:StufaturaType" minOccurs="0"/>
      <!-- Optional 1.00: hoop/cloth forming and grain salting (обсушка / засолка в зерне). -->
      <xs:element name="FORMING" minOccurs="0">
        <xs:complexType>
          <xs:attribute name="method" type="xs:token" use="optional"/>
        </xs:complexType>
      </xs:element>
      <xs:element name="GRAIN_SALT" minOccurs="0">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="AMOUNT" type="cx:AmountType" minOccurs="0"/>
          </xs:sequence>
          <xs:attribute name="method" type="xs:token" use="optional"/>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="WashWaterType">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        Curd-wash water: volume and temperature of the water added after a
        whey draw (Colby, brick, cabra al vino, gouda-family).
      </xs:documentation>
      <xs:documentation xml:lang="ru">
        Промывочная вода: объём и температура воды, которую доливают после
        отбора сыворотки (колби, брик, кабра аль вино, семейство гауды).
      </xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="VOLUME" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="TEMP" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="NOTES" type="cx:LocalizedText" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="RampType">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        Temperature ramp used when cooking or scalding curd: heat FROM one
        temperature TO another over an optional DURATION (cheddar, alpine, gouda).
      </xs:documentation>
      <xs:documentation xml:lang="ru">
        Нагрев зерна: от температуры FROM до TO за необязательное DURATION
        (чеддер, альпийские, гауда).
      </xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="FROM" type="cx:Quantity"/>
      <xs:element name="TO" type="cx:Quantity"/>
      <xs:element name="DURATION" type="cx:Quantity" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="HoldType">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        Hold at a temperature (paneer hold at 85–90 °C before cooling).
      </xs:documentation>
      <xs:documentation xml:lang="ru">
        Выдержка при температуре (панир держат при 85–90 °C перед охлаждением).
      </xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="TEMP" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="DURATION" type="cx:Quantity" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="CoolType">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        Cool the vat TO a target temperature after a hold or cook.
      </xs:documentation>
      <xs:documentation xml:lang="ru">
        Охлаждение ванны до целевой температуры после выдержки или постановки.
      </xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="TO" type="cx:Quantity"/>
      <xs:element name="DURATION" type="cx:Quantity" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="RateType">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        Heating or cooling rate: @value @unit per @per (e.g. 1 °C per min).
        Optional @every: 1 °C per 5 min is value="1" unit="C" per="min" every="5".
      </xs:documentation>
      <xs:documentation xml:lang="ru">
        Скорость нагрева или охлаждения: @value @unit за @per (например 1 °C в минуту).
        Необязательный @every: 1 °C за 5 мин — value="1" unit="C" per="min" every="5".
      </xs:documentation>
    </xs:annotation>
    <xs:attribute name="value" type="xs:decimal" use="required"/>
    <xs:attribute name="unit" type="cx:UnitCode" use="required"/>
    <xs:attribute name="per" type="cx:UnitCode" use="required"/>
    <xs:attribute name="every" type="xs:decimal" use="optional"/>
  </xs:complexType>

  <xs:complexType name="StirType">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        Stirring protocol. @intensity is a code (gentle, moderate, vigorous,
        none, top_bottom). Optional @every/@unit is the interval; DURATION is
        how long stirring lasts.
      </xs:documentation>
      <xs:documentation xml:lang="ru">
        Протокол вымешивания. @intensity — код (gentle, moderate, vigorous,
        none, top_bottom). @every/@unit — интервал; DURATION — сколько мешать.
      </xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="DURATION" type="cx:Quantity" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="intensity" type="cx:Code" use="optional"/>
    <xs:attribute name="every" type="xs:decimal" use="optional"/>
    <xs:attribute name="unit" type="cx:UnitCode" use="optional"/>
  </xs:complexType>

  <xs:complexType name="CutType">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        How the coagulum is cut. Cube size stays on PARAMS/SIZE;
        @pattern is a code (checkerboard, ladle, vertical, mill, random, cubes, columns).
        Optional @axis is horizontal, vertical or both.
      </xs:documentation>
      <xs:documentation xml:lang="ru">
        Как режут сгусток. Размер куба — PARAMS/SIZE;
        @pattern — код (checkerboard, ladle, vertical, mill, random, cubes, columns).
        @axis — horizontal, vertical или both.
      </xs:documentation>
    </xs:annotation>
    <xs:attribute name="pattern" type="cx:Code" use="optional"/>
    <xs:attribute name="axis" type="cx:Code" use="optional"/>
  </xs:complexType>

  <xs:complexType name="UntilType">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        Qualitative or pH end-condition of the step (clean_break, whey_clear,
        stretch, knitted, squeaky, robe, firm, custard, ph). Optional PH
        child when code is ph.
      </xs:documentation>
      <xs:documentation xml:lang="ru">
        Качественное или pH-условие конца шага (clean_break, whey_clear,
        stretch, knitted, squeaky, robe, firm, custard, ph). Дочерний PH
        — когда code="ph".
      </xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="PH" type="cx:PhType" minOccurs="0"/>
      <xs:element name="NOTES" type="cx:LocalizedText" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="code" type="cx:Code" use="required"/>
  </xs:complexType>

  <xs:complexType name="DrainType">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        How whey is separated: hanging bag, vat, cloth, hoop, colander, table.
      </xs:documentation>
      <xs:documentation xml:lang="ru">
        Как отделяют сыворотку: подвес, ванна, ткань, форма, дуршлаг, стол.
      </xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="DURATION" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="NOTES" type="cx:LocalizedText" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="method" type="cx:Code" use="optional"/>
  </xs:complexType>

  <xs:complexType name="VatAdditionType">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        BeerXML-like vat addition at this step (culture, lipase, CaCl2, rennet).
        AMOUNT uses AmountType @basis (batch or per_l). Optional DILUTE_IN and REST.
      </xs:documentation>
      <xs:documentation xml:lang="ru">
        Внесение в ванну на этом шаге, как HOP/MISC в BeerXML (закваска, липаза,
        CaCl2, фермент). AMOUNT с @basis (batch или per_l). DILUTE_IN и REST по желанию.
      </xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="AMOUNT" type="cx:AmountType" minOccurs="0"/>
      <xs:element name="DILUTE_IN" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="REST" type="cx:Quantity" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="role" type="cx:IngredientRole" use="required"/>
    <xs:attribute name="ref" type="cx:Id" use="optional"/>
  </xs:complexType>

  <xs:complexType name="CutsType">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        Ordered cuts of the coagulum (horizontal then vertical, 1 cm columns).
        Analogous to BeerXML MASH_STEPS.
      </xs:documentation>
      <xs:documentation xml:lang="ru">
        Последовательная нарезка сгустка (горизонталь, затем вертикаль, колонны 1 см).
        Как MASH_STEPS в BeerXML.
      </xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="CUT" maxOccurs="unbounded">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="SIZE" type="cx:Quantity" minOccurs="0"/>
            <xs:element name="WAIT" type="cx:Quantity" minOccurs="0"/>
          </xs:sequence>
          <xs:attribute name="n" type="xs:positiveInteger" use="required"/>
          <xs:attribute name="axis" type="cx:Code" use="optional"/>
          <xs:attribute name="pattern" type="cx:Code" use="optional"/>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="SettleType">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        Grain rest / heal (осаживание зерна) after cutting or stirring.
      </xs:documentation>
      <xs:documentation xml:lang="ru">
        Осаживание зерна после нарезки или промеса.
      </xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="DURATION" type="cx:Quantity" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="kind" type="cx:Code" use="optional"/>
  </xs:complexType>

  <xs:complexType name="FlipsType">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        Numbered flip schedule in the hoop or during stufatura
        (5 min, then +15 min, then three steam-bath turns). Distinct from
        periodic FLIP@every.
      </xs:documentation>
      <xs:documentation xml:lang="ru">
        Нумерованный график переворотов в форме или в стуфатуре
        (5 мин, затем +15 мин, затем три оборота в паровой бане).
        Это не периодический FLIP@every.
      </xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="FLIP" maxOccurs="unbounded">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="AFTER" type="cx:Quantity" minOccurs="0"/>
          </xs:sequence>
          <xs:attribute name="n" type="xs:positiveInteger" use="required"/>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="StufaturaType">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        Warm knit / stufatura. @medium is steam, water_bath or air.
        TEMP is the steam or bath temperature, not a press load.
      </xs:documentation>
      <xs:documentation xml:lang="ru">
        Стуфатура / паровая баня. @medium — steam, water_bath или air.
        TEMP — температура пара или бани, не груз пресса.
      </xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="TEMP" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="DURATION" type="cx:Quantity" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="medium" type="cx:Code" use="optional"/>
  </xs:complexType>

  <xs:complexType name="PackagingType">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        Finishing wrap of the wheel: wax, cloth_bound, vacuum, brine, oil,
        plastic, paper, natural, none. Distinct from AGING/RIND (what the
        rind becomes) — this is how the make is packed.
      </xs:documentation>
      <xs:documentation xml:lang="ru">
        Финишная упаковка головки: wax, cloth_bound, vacuum, brine, oil,
        plastic, paper, natural, none. Это не корка (AGING/RIND), а способ
        упаковать готовый сыр.
      </xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="NOTES" type="cx:LocalizedText" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="method" type="cx:Code" use="required"/>
  </xs:complexType>

  <xs:complexType name="BrineType">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        Explicit brine formula used by almost every brined or washed-rind
        home recipe: water + salt + optional CaCl2 + optional acid, at a
        given temperature. @saturated="true" means a fully saturated brine
        (~26% salt, typically 2.25 lb salt per gallon of water).
      </xs:documentation>
      <xs:documentation xml:lang="ru">
        Явная формула рассола: вода + соль + необязательные CaCl2 и кислота,
        при заданной температуре. saturated="true" — насыщенный рассол
        (~26% соли, обычно 2,25 фунта соли на галлон воды).
      </xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="WATER" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="SALT" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="CACL2" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="ACID" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="TEMP" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="DURATION" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="NOTES" type="cx:LocalizedText" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="saturated" type="xs:boolean" use="optional"/>
    <xs:attribute name="hours_per_kg" type="xs:decimal" use="optional"/>
    <xs:attribute name="salt_target_pct" type="xs:decimal" use="optional"/>
  </xs:complexType>

  <xs:complexType name="WheyType">
    <xs:sequence>
      <xs:element name="NOTES" type="cx:LocalizedText" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="retain" type="xs:boolean" use="optional" default="false"/>
    <xs:attribute name="use" type="cx:Code" use="optional"/>
  </xs:complexType>

  <xs:complexType name="TargetsType">
    <xs:sequence>
      <xs:element name="MOISTURE" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="FAT_IN_DM" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="SALT" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="PH_24H" type="cx:PhType" minOccurs="0"/>
      <xs:element name="PH_FINAL" type="cx:PhType" minOccurs="0"/>
      <xs:element name="PH_MILK" type="cx:PhType" minOccurs="0"/>
      <xs:element name="PH_DRAIN" type="cx:PhType" minOccurs="0"/>
      <xs:element name="PH_SALT" type="cx:PhType" minOccurs="0"/>
      <xs:element name="PH_CUT" type="cx:PhType" minOccurs="0"/>
      <xs:element name="PH_MILL" type="cx:PhType" minOccurs="0"/>
      <xs:element name="PH_DEMOLD" type="cx:PhType" minOccurs="0"/>
      <xs:element name="MNFS" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="S_M" type="cx:Quantity" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="AgingType">
    <xs:sequence>
      <xs:element name="DURATION" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="STAGE" type="cx:AgingStageType" maxOccurs="unbounded"/>
      <xs:element name="NOTES" type="cx:LocalizedText" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="AgingStageType">
    <xs:sequence>
      <xs:element name="NAME" type="cx:LocalizedText" minOccurs="0"/>
      <xs:element name="DURATION" type="cx:Quantity"/>
      <xs:element name="TEMP" type="cx:Quantity"/>
      <xs:element name="HUMIDITY" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="RIND" type="cx:CodedTerm" minOccurs="0"/>
      <xs:element name="TURNING" minOccurs="0">
        <xs:complexType>
          <xs:attribute name="every" type="xs:decimal" use="required"/>
          <xs:attribute name="unit" type="cx:UnitCode" use="required"/>
        </xs:complexType>
      </xs:element>
      <xs:element name="WASH" minOccurs="0">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="VOLUME" type="cx:Quantity" minOccurs="0"/>
            <xs:element name="NOTES" type="cx:LocalizedText" minOccurs="0"/>
          </xs:sequence>
          <xs:attribute name="code" type="cx:Code" use="optional"/>
          <xs:attribute name="every" type="xs:decimal" use="optional"/>
          <xs:attribute name="unit" type="cx:UnitCode" use="optional"/>
          <xs:attribute name="medium" type="xs:token" use="optional"/>
        </xs:complexType>
      </xs:element>
      <xs:element name="NOTES" type="cx:LocalizedText" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="n" type="xs:positiveInteger" use="required"/>
    <xs:attribute name="code" type="cx:Code" use="optional"/>
  </xs:complexType>

  <xs:complexType name="SensoryType">
    <xs:sequence>
      <xs:element name="TEXTURE" type="cx:CodedTerm" minOccurs="0"/>
      <xs:element name="FLAVOR" type="cx:CodedTerm" minOccurs="0" maxOccurs="unbounded"/>
      <xs:element name="AROMA" type="cx:CodedTerm" minOccurs="0" maxOccurs="unbounded"/>
      <xs:element name="NOTES" type="cx:LocalizedText" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="StorageType">
    <xs:sequence>
      <xs:element name="TEMP" type="cx:Quantity"/>
      <xs:element name="SHELF_LIFE" type="cx:Quantity" minOccurs="0"/>
      <xs:element name="NOTES" type="cx:LocalizedText" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="AllergensType">
    <xs:sequence>
      <xs:element name="ALLERGEN" maxOccurs="unbounded">
        <xs:complexType>
          <xs:attribute name="code" type="cx:Code" use="required"/>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="SourceType">
    <xs:sequence>
      <xs:element name="TITLE" type="cx:LocalizedText" minOccurs="0"/>
      <xs:element name="CREATOR" type="cx:LocalizedText" minOccurs="0"/>
      <xs:element name="YEAR" type="xs:gYear" minOccurs="0"/>
      <xs:element name="URL" type="xs:anyURI" minOccurs="0"/>
      <xs:element name="NOTES" type="cx:LocalizedText" minOccurs="0"/>
      <xs:element name="STANDARD" type="xs:token" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute name="kind" type="xs:token" use="optional"/>
  </xs:complexType>

  <xs:complexType name="RelatedType">
    <xs:attribute name="recipe" type="cx:Id" use="required"/>
    <xs:attribute name="relation" type="cx:RelationKind" use="required"/>
  </xs:complexType>

  <xs:complexType name="TagsType">
    <xs:sequence>
      <xs:element name="TAG" maxOccurs="unbounded">
        <xs:complexType>
          <xs:attribute name="code" type="cx:Code" use="required"/>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="ExtensionType">
    <xs:annotation>
      <xs:documentation>
        Forward-compatible bag of typed key/value fields. Software that
        does not understand a key MUST ignore it.
      </xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="FIELD" minOccurs="0" maxOccurs="unbounded">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="NAME" type="cx:LocalizedText" minOccurs="0"/>
            <xs:element name="VALUE" type="xs:string" minOccurs="0"/>
            <xs:element name="TEXT" type="cx:LocalizedText" minOccurs="0"/>
          </xs:sequence>
          <xs:attribute name="key" type="xs:token" use="required"/>
          <xs:attribute name="type" use="optional" default="string">
            <xs:simpleType>
              <xs:restriction base="xs:token">
                <xs:enumeration value="string"/>
                <xs:enumeration value="number"/>
                <xs:enumeration value="boolean"/>
                <xs:enumeration value="text"/>
              </xs:restriction>
            </xs:simpleType>
          </xs:attribute>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>

  <!-- ============================================================ -->
  <!-- Vocabularies (optional companion document)                    -->
  <!-- ============================================================ -->

  <xs:element name="VOCABULARIES">
    <xs:annotation>
      <xs:documentation xml:lang="en">
        Companion document mapping machine codes to localized labels.
        Not required inside a recipe file; software SHOULD ship or fetch
        a vocabulary pack so UIs can render codes in the user's language.
      </xs:documentation>
    </xs:annotation>
    <xs:complexType>
      <xs:sequence>
        <xs:element name="VOCABULARY" maxOccurs="unbounded">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="TERM" maxOccurs="unbounded">
                <xs:complexType>
                  <xs:sequence>
                    <xs:element name="LABEL" type="cx:LocalizedText"/>
                    <xs:element name="DEFINITION" type="cx:LocalizedText" minOccurs="0"/>
                  </xs:sequence>
                  <xs:attribute name="code" type="xs:token" use="required"/>
                </xs:complexType>
              </xs:element>
            </xs:sequence>
            <xs:attribute name="id" type="xs:token" use="required"/>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
      <xs:attribute name="version" type="cx:SchemaVersion" use="required"/>
      <xs:attribute name="defaultLang" type="cx:LangCode" use="optional"/>
    </xs:complexType>
  </xs:element>

</xs:schema>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Кэширование объекта 0/177 объектов с помощью Redis
Кэширование страницы с использованием Redis 
CDN через N/A
Отложенная загрузка

Served from: www.samovar-tool.ru @ 2026-09-14 06:04:24 by W3 Total Cache
-->