Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 

Repository files navigation

xmlvalidate

Bulk XML schema validation for California Revealed preservation packages. A single cross-platform Python tool that recursively scans a directory (typically an external hard drive containing vendor deliverables), validates every metadata record it finds against the appropriate schema, and writes both a combined CSV and a human-readable validation report per partner organization.

xmlvalidate.py replaces the earlier zsh-based DCandPBCore_validation script and runs identically on Apple silicon macOS, Intel macOS, and Windows.

What it validates

The tool discovers and validates two profiles of XML files anywhere under the target directory:

Files matching Validated against Profile name
*metadata.xml CA-R Dublin Core entry-point schema (CA-R_metadata.xsd, which imports CA-Rdqdcterms.xsd) metadata
*pbcore.xml PBCore 2.1 schema (pbcore-2_1.xsd) pbcore

Validation is fully offline. The bundled schemas/catalog.xml redirects every remote schema import (dublincore.org, w3.org, pbcore.org) to the local copies in the schemas/ folder, so the tool works with no network connection and never silently fetches anything from the internet.

macOS and Windows filesystem clutter is skipped automatically: .Trashes, .Spotlight-V100, .fseventsd, $RECYCLE.BIN, System Volume Information, AppleDouble ._* files, .DS_Store, Thumbs.db, and anything else hidden.

Repository layout

xmlvalidate/
├── xmlvalidate.py          The tool. One file, no editing required.
├── schemas/
│   ├── catalog.xml         Portable XML catalog (relative paths — do not edit)
│   ├── CA-R_metadata.xsd   Entry-point schema for DC metadata records (accepts both root styles)
│   ├── CA-Rdqdcterms.xsd   CA-R qualified Dublin Core schema (imported by the above)
│   ├── pbcore-2_1.xsd      PBCore 2.1 schema
│   ├── dc.xsd              Dublin Core elements (imported)
│   ├── dcterms.xsd         Dublin Core terms (imported)
│   ├── dcmitype.xsd        DCMI type vocabulary (imported)
│   └── xml.xsd             W3C xml namespace schema (imported)
├── README.md
└── CHANGELOG.md

Keep xmlvalidate.py and the schemas/ folder together. The script finds its schemas relative to its own location, so the whole folder can live anywhere — a Tools directory, a Desktop, even the external drive itself.

Installation

Requirements: Python 3.8 or newer, plus the lxml package. No virtual environment is needed.

macOS (Apple silicon and Intel). Recent macOS does not ship Python 3 by itself; install it once from python.org (the universal installer covers both architectures), or via Homebrew. Then:

pip3 install lxml

If Homebrew's Python refuses with an "externally managed environment" message, use pip3 install lxml --break-system-packages (safe for a single, widely-used package like lxml) or pip3 install --user lxml.

Windows. Install Python 3 from python.org and check "Add python.exe to PATH" during setup. Then in PowerShell or Command Prompt:

py -m pip install lxml

That's the entire installation. To get the tool itself, either clone this repository or download it as a ZIP (green Code button → Download ZIP) and unzip it anywhere.

Usage

Interactive (no arguments)

Run the script with no arguments and it will prompt you, just like the original zsh tool:

macOS:    python3 xmlvalidate.py
Windows:  py xmlvalidate.py
Enter the directory to scan: /Volumes/CA-R_Drive/CA-R2082
Combined CSV path [/Volumes/CA-R_Drive/CA-R2082/XMLvalidationCombined_2026-07-27.csv]:

Press Enter at the CSV prompt to accept the default. Paths dragged into the terminal from Finder or File Explorer work fine, including paths with spaces.

With flags

python3 xmlvalidate.py --dir "/Volumes/CA-R_Drive/CA-R2082"
py xmlvalidate.py --dir "E:\CA-R2082" --csv "E:\reports\combined.csv"
Flag Purpose
-d, --dir PATH Directory to scan recursively
--csv PATH Where to write the combined CSV (default: inside the scanned directory, dated)
--dry-run List the files that would be validated; validate nothing, write nothing
--no-log Skip the per-MARC-code .txt report files
-q, --quiet Suppress per-file progress lines; print only the summary
--schemas-dir PATH Use a different schemas folder
--schema-metadata / --schema-pbcore / --catalog PATH Override individual schema or catalog paths
--version Print the tool version

Outputs

Combined CSV — one row per file with columns profile, file, status, errors. Written to the scanned directory by default (e.g., XMLvalidationCombined_2026-07-27.csv), or wherever --csv points.

Per-partner validation reports — one plain-text report per MARC organization code found in the scan, written to the parent directory of that MARC code's folder. Every run gets its own report file, named with the run's date and time:

[marc]_XMLvalidationReport_[YYYY-MM-DD]_[HHMMSS].txt

For example, scanning a shipment folder CA-R2082/ containing camtrcsp/ and chi/ subfolders produces:

CA-R2082/
├── camtrcsp_XMLvalidationReport_2026-07-27_163009.txt
├── chi_XMLvalidationReport_2026-07-27_163009.txt
├── camtrcsp/
│   └── camtrcsp_000001/ ...
└── chi/
    └── chi_000039/ ...

Each report records the run timestamp, the scanned path, the schemas used, a line per file with its VALID/INVALID status, any validation errors (with line numbers), and a summary count. Because the run time is part of the file name, repeated runs never overwrite earlier reports — each run's results stay in their own file. The MARC code is read from the file names themselves (e.g., camtrcsp_000123_metadata.xmlcamtrcsp); if a file's location doesn't include a folder named for its MARC code, its report falls back to the scanned directory.

Exit codes

Consistent with California Revealed's other command-line tools:

  • 0 — every file validated successfully
  • 1 — one or more files were invalid or not well-formed
  • 2 — configuration or usage error (missing directory, missing schemas, lxml not installed)

This makes the tool safe to chain in scripts: python3 xmlvalidate.py --dir "$DIR" && echo "All valid".

Troubleshooting

"The lxml package is not installed." Run the pip command from the Installation section for your platform. On Windows, if py isn't recognized, reinstall Python and enable "Add python.exe to PATH."

"Required metadata schema not found." The schemas/ folder isn't next to xmlvalidate.py. Keep the repository folder intact, or point at the schemas explicitly with --schemas-dir.

Zero files found. Check that the file names end in metadata.xml or pbcore.xml (case-insensitive) and that the drive is actually mounted at the path you entered. Use --dry-run to see exactly what the tool discovers.

Report can't be written (read-only or locked drive). The tool warns you and writes the report into the scanned directory instead; validation results are never lost.

A file passes validation that "looks wrong." The entry-point schema validates the metadata root's children laxly: elements declared in the dc/dcterms/dcmitype schemas are fully validated (including typed content such as W3CDTF dates), while undeclared elements are skipped. Schema-valid is not the same as content-correct. To require that every child element be declared, change processContents="lax" to "strict" in CA-R_metadata.xsd.

All metadata files fail with "No matching global declaration available for the validation root." You are probably validating against CA-Rdqdcterms.xsd directly (e.g., via --schema-metadata). Vendor records use an unqualified <metadata> root, which that schema alone cannot match; validate against CA-R_metadata.xsd (the default), which accepts both unqualified and dcterms-namespaced roots.

Notes on the schemas and catalog

One schema carries a documented California Revealed modification: dc.xsd adds a single optional type attribute to the DCMI SimpleLiteral type, because CA-R vendor records qualify Dublin Core elements this way (e.g., <dc:date type="Published">, <dc:identifier type="CDNP identifier">). The change is marked with a comment in the file; deleting that one attribute line restores canonical DCMI behavior.

The catalog uses relative paths that resolve against the catalog file's own location, which is what makes the folder portable across operating systems, users, and drive letters. If you replace a schema (for example, a future PBCore revision), keep the filename or update both the script defaults and catalog.xml. The catalog covers http and https variants of every import URL used by the schemas.

License

See LICENSE.

About

Python based bulk XML schema validation for California Revealed PBCore and Dublin Core XML.

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages