Metadata-Version: 2.3
Name: prettyxsd
Version: 0.6.0
Summary: Generate browsable static HTML documentation from XSD schemas
Author: Giles Antonio Radford
Author-email: Giles Antonio Radford <moof@metamoof.net>
Requires-Dist: click>=8.5.0
Requires-Dist: jinja2>=3.1.6
Requires-Dist: markdown>=3.11
Requires-Dist: pygments>=2.21.0
Requires-Python: >=3.14
Description-Content-Type: text/markdown

# prettyxsd

Generate a browsable, static HTML reference from XML Schema Definition (XSD) files. The output includes an element index, a searchable global-element sidebar, pages for global elements and named types, links between declarations, and local CSS/JavaScript assets. The generated site can be opened locally or hosted as a static site; it does not require a web server or network connection.

## Requirements

- Python 3.14 or newer
- [`uv`](https://docs.astral.sh/uv/)

## Install and run

From this directory, sync the project and run the CLI with `uv`:

```sh
uv sync
uv run prettyxsd --input path/to/schema.xsd --output path/to/site
```

Use `--input` more than once to provide multiple schema entry points:

```sh
uv run prettyxsd \
  --input schemas/main.xsd \
  --input schemas/another-entry-point.xsd \
  --output docs/
```

Use `--title` to set the documentation title shown in the sidebar and browser tab (default `prettyxsd`), and `--logo` to replace the default mark at the top left with an image file, which is copied into the site's `assets/` directory:

```sh
uv run prettyxsd --input schemas/main.xsd --output docs/ --title "NeTEx" --logo netex-logo.png
```

The command recursively resolves relative local `xsd:include` and `xsd:import` schema locations. Remote schema locations are intentionally not fetched. Missing local dependencies and remote locations are reported as notices in the terminal and generated site; generation continues with the schemas it could load.

To link declarations to their source file and line on GitHub, pass the GitHub URL for the directory containing the first input XSD. For example, NeTEx `NX.xsd` is in `xsd/`, so use:

```sh
uv run prettyxsd \
  --input ../NeTEx/xsd/NX.xsd \
  --output docs/netex \
  --github-base-url https://github.com/TransmodelEcosystem/NeTEx/tree/v2.0/xsd
```

The option follows locally included schemas under the same directory and emits links to GitHub `blob` URLs with line anchors. Clickable source links are omitted for declarations outside that directory or when the option is not supplied.

Every declaration (elements, types, attributes, child elements/tree nodes, and enumeration values) always shows its defining schema file and line number as plain text (e.g. `netex_transportOrganisation_version.xsd:287`), regardless of whether `--github-base-url` is set. The `--github-base-url` option only adds a clickable link on top of that always-visible location.

Open `docs/index.html` in a browser to browse the generated documentation. The index tree is rooted in global elements declared by the supplied entry-point schema files; local structure is expanded and named model groups (`xsd:group`) are kept as labelled branches, while referenced global elements link to their detail pages. Declarations brought in only by includes/imports remain available in the reference list and sidebar without overwhelming the top-level tree. This supports organization schemas such as NeTEx `NX.xsd`, whose `Nx` element provides a useful browsing hierarchy.

## What is documented

- Global elements, with one page per element
- Element documentation rendered as Markdown, including supported inline XSD markup
- Child elements, occurrence ranges, referenced global elements, and types
- Named model groups, shown as `group` branches in the content model with the group's own documentation and occurrence range
- Anonymous `xsd:choice` compositors with more than one alternative, shown as a `choice` branch so alternatives aren't misread as a required sequence
- Anonymous `xsd:sequence`/`xsd:all` compositors that repeat, are optional, or carry their own documentation, shown as a labelled branch instead of being silently flattened away
- Attributes, required/optional use, referenced types, documentation, and any `default`/`fixed` value
- Elements with a `default`/`fixed` value, shown inline in the content-model tree
- Named simple and complex types, with links from elements and child declarations
- Simple type restrictions (`minInclusive`, `maxInclusive`, `minExclusive`, `maxExclusive`, `minLength`, `maxLength`, `length`, `totalDigits`, `fractionDigits`, `whiteSpace`, `pattern`), listed alongside the base type they narrow
- Abstract elements and types, flagged with an `abstract` badge wherever they appear (their own page, substitution-group listings, content-model trees, and the global element list) since they cannot be used directly in an instance document
- Known subtypes of a complex or simple type ("Derived types"), linked from the base type's page
- `xsd:list` simple types, showing the linked item type ("Item type")
- `xsd:union` simple types, showing each linked member type ("Member types"); inline anonymous member types are described in place (e.g. their restriction base and enumeration values) since they have no page of their own
- The full substitution-group ancestry chain for an element ("Substitution group chain"), not just its immediate parent, so a deeply nested element like NeTEx's `Operator` shows its whole path back to the ultimate abstract root (`Operator → TransportOrganisation_Dummy → Organisation_Dummy → DataManagedObject → EntityInVersion`)
- The full set of concrete elements reachable transitively through an element's substitution-group descendants ("Concrete substitution alternatives"), so an abstract root element's page lists every element that can actually be used in its place in an instance document, not just its immediate substitution members
- Identity constraints (`xsd:key`, `xsd:keyref`, `xsd:unique`) declared directly on an element, listed in an "Identity constraints" table with their selector/field XPath expressions and documentation; a `keyref`'s `refer` is resolved and linked to the `key`/`unique` it targets (which may be on the same or a different element's page), falling back to plain text when the target can't be resolved

Generated detail pages are grouped under `elements/<namespace>/<name>.html` and `types/<namespace>/<name>.html`. The path segments are readable slugs; a short hash is added only when distinct names would otherwise collide. Shared assets remain under `assets/`, and nested pages use relative links so the site works locally and when hosted under a subdirectory.

XSD documentation is rendered as Markdown, with supported inline XSD markup preserved. The generated HTML is then passed through a conservative allowlist sanitizer: unsafe elements are not emitted as HTML, and unsafe link schemes are removed. Legacy inline option markers such as `for:- …, or- …` are formatted as Markdown lists.

## Development

Dependencies and lockfile are managed with `uv` (do not use `pip`):

```sh
uv sync
uv run python -m unittest discover -s tests -v
```

See [PLAN.md](PLAN.md) for the implementation scope and design decisions.
