{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "oasis:dita-metadata:1.3",
  "title": "DITA 1.3 document metadata",
  "description": "The typed metadata elements OASIS defines for a DITA topic or map, as docmeta reads them. Named `dita-metadata` rather than `dita-prolog` because it constrains `topicmeta.*` too, and a name saying prolog would be wrong for every map. Keys follow docmeta's element rule — the containing element is the namespace — so a topic's `<prolog><metadata><audience>` is `metadata.audience` while a map's `<topicmeta><audience>` is `topicmeta.audience`. That is not a quirk: the OASIS content model makes them peers under `<topicmeta>` and nests them under `<prolog>` in a topic, and each key names where the value actually is. Cardinality is taken from the content model, so `author*` is a list and `source?` is a scalar. Requires nothing: DITA marks no metadata element mandatory. The `<othermeta name= content=>` channel keeps its flat keys and is not described here — a document may carry both, and both are validated. See https://docs.oasis-open.org/dita/dita/v1.3/os/part1-base/langRef/containers/prolog-elements.html",
  "type": "object",
  "additionalProperties": true,
  "$defs": {
    "textList": {
      "type": "array",
      "items": { "type": "string" }
    },
    "scalarList": {
      "type": "array",
      "items": { "type": ["string", "number"] },
      "description": "Attribute values are parsed as YAML scalars, as they are in every format docmeta reads, so `year=\"2026\"` arrives as the number 2026 while `version=\"2.1.0\"` stays a string. Both are accepted rather than the reader special-casing these attributes, which would be a surprise nothing else in the tool prepares you for."
    },
    "ditaDate": {
      "type": "string",
      "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
      "description": "A `YYYY-MM-DD` date. DITA types these attributes as CDATA, so the DTD itself imposes no format — this is the convention DITA-OT and every toolchain around it assume, checked here because a date nothing validates is a date that drifts."
    }
  },
  "properties": {
    "prolog.author": {
      "$ref": "#/$defs/textList",
      "description": "Topic authors, from `<prolog><author>`. A list: the content model is `author*`."
    },
    "prolog.source": {
      "type": "string",
      "description": "The resource this topic derives from, from `<prolog><source>`. Scalar: `source?`."
    },
    "prolog.publisher": {
      "type": "string",
      "description": "Who makes the topic available, from `<prolog><publisher>`. Scalar: `publisher?`."
    },
    "prolog.permissions": {
      "type": "string",
      "description": "Entitlement required to view the topic, from `<permissions @entitlement>`. Not enumerated — DITA suggests values without fixing them."
    },
    "prolog.resourceid": {
      "$ref": "#/$defs/textList",
      "description": "Application-specific identifiers, from `<resourceid @id>`. A list: `resourceid*`."
    },
    "topicmeta.author": {
      "$ref": "#/$defs/textList",
      "description": "Map authors, from `<topicmeta><author>`. The map spelling of `prolog.author`."
    },
    "topicmeta.source": {
      "type": "string",
      "description": "The map spelling of `prolog.source`."
    },
    "topicmeta.publisher": {
      "type": "string",
      "description": "The map spelling of `prolog.publisher`."
    },
    "topicmeta.permissions": {
      "type": "string",
      "description": "The map spelling of `prolog.permissions`."
    },
    "topicmeta.resourceid": {
      "$ref": "#/$defs/textList",
      "description": "The map spelling of `prolog.resourceid`."
    },
    "topicmeta.audience": {
      "$ref": "#/$defs/textList",
      "description": "Intended audiences, from `<topicmeta><audience @type>`. A map holds these directly; a topic nests them, where they are `metadata.audience`."
    },
    "topicmeta.category": {
      "$ref": "#/$defs/textList",
      "description": "Categories, from `<topicmeta><category>`. The map spelling of `metadata.category`."
    },
    "critdates.created": {
      "$ref": "#/$defs/ditaDate",
      "description": "Creation date, from `<critdates><created @date>`. Scalar: `created?`. Identical in topics and maps, because the containing element is the same in both."
    },
    "critdates.revised": {
      "type": "array",
      "items": { "$ref": "#/$defs/ditaDate" },
      "description": "Revision dates, from `<critdates><revised @modified>`. A list: `revised*`."
    },
    "metadata.audience": {
      "$ref": "#/$defs/textList",
      "description": "Intended audiences in a topic, from `<prolog><metadata><audience @type>`. A list: `audience*`. Not enumerated — the values are a project's own vocabulary."
    },
    "metadata.category": {
      "$ref": "#/$defs/textList",
      "description": "Categories in a topic, from `<prolog><metadata><category>`. A list: `category*`."
    },
    "prodinfo.prodname": {
      "type": "string",
      "description": "Product name, from `<prodinfo><prodname>`. Scalar: `prodname?`."
    },
    "prodinfo.brand": {
      "$ref": "#/$defs/textList",
      "description": "Manufacturer or brand, from `<prodinfo><brand>`."
    },
    "prodinfo.component": {
      "$ref": "#/$defs/textList",
      "description": "Product component, from `<prodinfo><component>`."
    },
    "prodinfo.featnum": {
      "$ref": "#/$defs/textList",
      "description": "Feature number, from `<prodinfo><featnum>`."
    },
    "prodinfo.platform": {
      "$ref": "#/$defs/textList",
      "description": "Operating system or hardware, from `<prodinfo><platform>`."
    },
    "prodinfo.prognum": {
      "$ref": "#/$defs/textList",
      "description": "Program or order number, from `<prodinfo><prognum>`."
    },
    "prodinfo.series": {
      "$ref": "#/$defs/textList",
      "description": "Product series, from `<prodinfo><series>`. These six are a repeatable *choice* group in the content model, so they may interleave in any order."
    },
    "vrm.version": {
      "$ref": "#/$defs/scalarList",
      "description": "Product version, from `<vrmlist><vrm @version>`. Keyed for the element rather than its container because `<vrm>` is EMPTY and carries three separate facts — keying it `vrmlist.vrm` would have to pick one and discard two. For an attribute the containing thing is the element, so the naming rule applies one level down rather than changing."
    },
    "vrm.release": {
      "$ref": "#/$defs/scalarList",
      "description": "Product release, from `<vrmlist><vrm @release>`. A `<vrm>` carrying no `@release` contributes nothing here, and is dropped from the element list with it, so a write still lands on the element its value came from."
    },
    "vrm.modification": {
      "$ref": "#/$defs/scalarList",
      "description": "Modification level, from `<vrmlist><vrm @modification>`."
    },
    "copyright.copyryear": {
      "$ref": "#/$defs/scalarList",
      "description": "Copyright years, from `<copyright><copyryear @year>`. A list: the content model is `copyryear+`."
    },
    "copyright.copyrholder": {
      "type": "string",
      "description": "Copyright holder, from `<copyright><copyrholder>`."
    },
    "keywords.keyword": {
      "$ref": "#/$defs/textList",
      "description": "Search keywords, from `<keywords><keyword>`. Reached through the children rather than the container: `<keywords>` holds `(indexterm | keyword)*` and has no text of its own."
    },
    "keywords.indexterm": {
      "$ref": "#/$defs/textList",
      "description": "Index terms, from `<keywords><indexterm>`. A *nested* `<indexterm>` makes its parent a container rather than a value, so only flat terms are lifted."
    }
  }
}
