Skip to content

fix(xmp): read tag lists with several items and single-Description sidecars - #1431

Open
gthb wants to merge 4 commits into
simulot:mainfrom
gthb:fix/xmp-sidecar-lists
Open

gthb wants to merge 4 commits into
simulot:mainfrom
gthb:fix/xmp-sidecar-lists

Conversation

@gthb

@gthb gthb commented Aug 22, 2026

Copy link
Copy Markdown

What

Fix XMP sidecar layouts that immich-go reads wrongly:

  • a digiKam:TagsList with more than one item applied no tags at all (a single item worked);
  • a description repeated in several languages (an rdf:Alt with more than one rdf:li) was dropped;
  • a sidecar with all its properties in one rdf:Description element yielded nothing but the GPS coordinates (description, date, rating and tags dropped).

Fixes #1430

Cause

walk appends an index to the elements of a list (Description[2], li[1]) and filter stripped only the index of the Description element, so a multi-item list's paths gained a li[N] segment and a single-Description sidecar's paths kept the /xmpmeta/RDF/Description/ prefix; neither matched the property names filter looks for. The GPS cases were written for the unindexed prefix, which is why only they worked in that layout (and they missed the indexed one). walk also reassigned its path variable on meeting a list, so the keys after the list in the same element got a wrong prefix.

Fix

filter strips every [N] index and the Description prefix before matching, and GPS is matched on the normalised path like the other properties. A multi-language description takes its first entry, which the XMP specification requires to be the x-default one. walk keeps the list path in a local variable.

Three sidecars are added as test data, one per layout, and the multi-Description one also covers GPS spread over several rdf:Description elements; the tests fail before the fix (expected 3 tags, got 0; the single-Description one loses description, date, rating and tags) and pass after.

Notes

Based on main rather than develop, because the fix was tested against Immich v3, whose support is on main only.

gthb added 4 commits August 19, 2026 13:59
Two XMP sidecars that the reader gets wrong:

- a digiKam:TagsList with more than one rdf:li: none of the tags is
  read (a single one is);
- all properties in one rdf:Description element: nothing but the GPS
  coordinates is read (description, date, rating and tags are dropped).
…decars

The reader walks the parsed document and matches property paths such as
"TagsList/Seq/li". walk appends an index to the elements of a list
("Description[2]", "li[1]"), and filter stripped only the index of the
Description element, so

- a tag list with several rdf:li items matched nothing: every item's
  path ended in "li[N]";
- a sidecar with a single rdf:Description matched nothing but GPS: its
  properties' paths kept the "/xmpmeta/RDF/Description/" prefix that
  filter only stripped when indexed, while the GPS cases were written
  for that unindexed form and missed the indexed one.

Strip every list index and the Description prefix before matching, and
match GPS on the normalised path like the other properties.

walk also reassigned its path variable when it met a list, so the keys
following the list in the same element were looked up under a wrong
prefix; use a local variable.
Before the fix, GPS coordinates were matched on the unindexed path only,
so they were read solely from sidecars with a single rdf:Description.
The multi-Description layout now works too, but no fixture exercised it;
add GPS to the multi-tags fixture to cover it.
Stripping the list indices made every rdf:li of an rdf:Alt match, so a
description repeated in several languages ended up as whichever entry
came last. The XMP specification puts the x-default entry first in an
Alt array, so keep the first match instead.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

XMP sidecars: a tag list with several items is ignored, and a sidecar with a single rdf:Description yields nothing but GPS

1 participant