Reading
Writing
Copying
Deleting
Field Names
Serialization
Examples
User-Defined

# Structured Information

ExifTool has the ability to read and write XMP structures through the use of either structured or flattened tags. The ability to write via structured input was added in ExifTool version 8.44; older versions accepted only flattened tags as input.

To illustrate the concept of a flattened tag, the `XMP-exif:Flash` structure contains `Fired` and `Mode` fields (among others). The flattened tags corresponding to these structure fields are `XMP-exif:FlashFired` and `XMP-exif:FlashMode`. In the XMP Tags documentation, flattened tags are indicated by an underline (`_`) after the Writable type.

This page describes various techniques used to read and write XMP structures using both structured and flattened tags.

## Reading

When reading, structures are flattened by default, and ExifTool returns one "flattened" tag for each field in the structure:

>     > exiftool -xmp:all a.xmp
>     XMP Toolkit                     : Image::ExifTool 8.44
>     Flash Fired                     : True
>     Flash Mode                      : On
>     Flash Return                    : Return not detected

But the `-struct` option may be used to give structured output. In this mode structures are returned instead of separate "flattened" tags:

>     > exiftool -struct -xmp:all a.xmp
>     XMP Toolkit                     : Image::ExifTool 8.44
>     Flash                           : {Fired=True,Mode=On,Return=Return not detected}

(Note: As illustrated in the example above, structures are serialized for console output by the ExifTool application. However, via the API with the `Struct` option, they are returned as Perl HASH references.)

The `-struct` option may also be combined with the JSON (`-j`), PHP (`-php`) or XML (`-X`) output formats to provide a structured format which may be more compatible with other applications.

## Writing

When writing, flattened tags and structures may be used interchangeably. For example, the following commands all have the same effect.

>     exiftool -flashmode=on -flashreturn=not -flashfired=true a.xmp
>     exiftool -xmp:flash="{mode=on,fired=true}" -flashreturn=not a.xmp
>     exiftool -xmp:flash="{mode=on,fired=true,return=not}" a.xmp

(Note: Structures must be serialized when writing via the command-line application, in the same format as when reading with the `-struct` option.)

An advantage of writing in structured form is that it can be easier to achieve the desired hierarchy with complex structures or when there are multiple structures in a list. For example, this command adds a new hierarchical keyword to the XMP-mwg-kw:HierarchicalKeywords list:

>     exiftool -hierarchicalkeywords+="{keyword=cat,children={keyword=Siamese}}" a.jpg

But the flattened tags may be more convenient for adding or replacing a single field in an existing structure because writing as a structure would require that the entire structure be replaced. For example, the following command adds a new second-level keyword to an existing HierarchicalKeywords structure:

>     exiftool -hierarchicalkeywords2+="Persian" a.jpg

Tricky: There is one drawback when using this technique to add new fields to existing structures in lists: New fields are added to the first structure which doesn't already contain the corresponding field. So before adding a new field to a arbitrary structure, dummy fields must first be added to all earlier structures in the list which are missing this field. However, the alternative of adding a new field by writing structured information also has its drawbacks. Here, although a specific structure in a list can easily be targeted through any unique combination of field values, the drawback is that the entire structure must be replaced (see Deleting / Replacing below).

The flattened tag names may also be used to write structures at any level in a complex hierarchy. The following example writes a third-level structure inside a HierarchicalKeywords structure:

>     exiftool -hierarchicalkeywords2Children='{Keyword=Tabby,Applied=true}' a.jpg

(Note: Containing structures are created as necessary. In this case, the HierarchicalKeywords and top-level KeywordInfo structures would be created if they didn't already exist.)

The order of structure fields is not significant, so they may be read in a different order than written, unlike arrays which maintain the same order. To give a predictable output, fields in structured information are sorted in alphabetical order of field name by ExifTool when reading and writing.

If there are errors converting some fields of the input structure, other fields are still written and a warning is issued (but only one warning per structure is reported). This also applies when copying structured information except that the `-v3` option must be used to see the warnings when copying.

Programmers: Structured information is written and read as Perl HASH references via the ExifTool API, but it may also be written as a serialized string. The following two techniques are equivalent:

>     # as a HASH reference
>     $exifTool->SetNewValue('XMP:Flash' => { mode=>'on', fired=>'true', return=>'not' });

>     # as a serialized string
>     $exifTool->SetNewValue('XMP:Flash' => '{mode=on,fired=true,return=not}');

## Copying

By default, tags are copied as structures, but flattened tag names may still be copied by specifying them explicitly. (Flattened tags are treated as "unsafe" for copying so they are not copied by default unless the Struct feature is disabled; see below.) Copying as structures allows the hierarchy of complex structures to be preserved.

>     # this copies all XMP information as structures
>     # (flattened tags are not copied by default...)
>     exiftool -tagsfromfile src.jpg -xmp:all dst.jpg

>     # ... but flattened tags may be copied individually.  Here the
>     # first level hierarchical keywords are copied to the Subject tag
>     # (this may be done in the same command as one that copies structures)
>     exiftool -tagsfromfile src.jpg "-subject<hierarchicalkeywords1" dst.jpg

Note that when copying a specific structure, only the top-level structures may be specified:

>     # this copies the complete keyword hierarchy
>     exiftool -tagsfromfile src.jpg -keywordinfo dst.jpg

>     # WRONG because HierarchicalKeywords is NOT a top-level structure!
>     exiftool -tagsfromfile src.jpg -hierarchicalkeywords dst.jpg

The copy-as-structure feature may be disabled with `--struct` on the command line, or by setting the Struct option to 0 via the API. When this is done, only flattened tags are copied, and structures may not be specified. Conversely, if the structure option is enabled (by setting the Struct option to 1 via the API, or with `-struct` on the command line), only structures are copied, and flattened tags may not be specified.

(Note: ExifTool 8.43 and earlier copied as flattened tags only, but copying as structures has been the default since the ability to write structured information was introduced in version 8.44. An enhancement in version 8.82 allowed flattened tags to be copied explicitly without the need to disable the Struct option.)

## Deleting / Replacing

A complete structure is deleted by specifying one or more matching fields. All fields must match for the structure to be deleted. For example, the following command deletes all HierarchicalKeywords structures which have the Keyword "`Terrier`" at the second level:

>     exiftool -hierarchicalkeywords-="{Children={Keyword=Terrier}}" a.jpg

Structure fields may also be deleted individually using the flattened tag names. The following command deletes only the matching fields from the second-level of all HierarchicalKeywords structures:

>     exiftool -hierarchicalkeywords2-="Terrier" a.jpg

Individual structure fields may NOT be deleted by writing a structure with an empty field. Instead, a command like this overwrites the entire structure with a new structure containing an empty field:

>     exiftool -CreatorContactInfo="{CiAdrCity=}" a.jpg  # WRONG!

When deleting and adding back items in lists in the same command, new items are inserted at the point in the list where the first item was removed, or at the end of the list if no items were deleted. This applies to lists of structures as well as simple lists of string values, and provides a mechanism to replace a specific structure or field.

## Field Names

Structure field names use a format very similar to tag names in ExifTool. The following table lists some similarities and differences between tag names and structure field names:

> Feature | Example | Tag Names | Field Names
> --- | --- | --- | ---
> Case Insensitivity | Title, title, TITLE | Yes | Yes
> Alternate Language Suffix | Title-de | Yes | Yes
> Numerical Value Suffix | Mode# | Yes | Yes
> Group Name Prefix | XMP-dc:Title | Yes | No†

> † Except that group name prefixes are allowed in structures which support arbitrary XMP fields (eg. Region Extensions)

## Serialization

Structures are serialized when reading or writing from the command line. However, serialization is not done when reading via the API, and is optional when writing via the API. The default serialization algorithm is outlined below, but note that ExifTool 12.64 has an API StructFormat option to allow JSON-format serialized structures.

Default serialization algorithm

1. Escape the following characters in string values (structure field values and list items) by adding a leading pipe symbol (`|`):
   - pipe symbols (`|`) and commas (`,`) anywhere in the string
   - closing curly brackets (`}`) anywhere in structure field values
   - closing square brackets (`]`) anywhere in list items
   - an opening curly (`{`) or square (`[`) bracket, or whitespace character (SPACE, TAB, CR or LF) if it appears at the beginning of the string
   (Note: Any other character may be escaped by adding a leading pipe symbol without effect.)
2. Enclose structures in curly brackets. Use an equal sign (`=`) to separate field names from their corresponding values, and a comma between structure fields.
3. Enclose lists in square brackets, with a comma between list items.
4. Optional whitespace padding may be added anywhere except inside a structure field name, or inside or after a string value, and an optional comma may be added after the last field in a structure.

For example, with this command:

>     exiftool "-RegionInfo<=INFILE" a.xmp

and the INFILE below, structured information is written to XMP-mwg-rs:RegionInfo.

>     {
>       AppliedToDimensions =
>       {
>          W = 4288,
>          H = 2848,
>          Unit = pixel,
>       },
>       RegionList =
>       [
>         {
>           Area =
>           {
>             W = 0.15, H = 0.17, X = 0.3, Y = 0.4,
>             Unit = normalized,
>           },
>           Description = A Physics Icon {relatively speaking|},
>           Name = Albert Einstein,
>           Type = Face,
>           Extensions = {
>             XMP-xmpRights:UsageTerms = copyright Phil Harvey,
>             XMP-xmpRights:UsageTerms-fr = droit d'auteur Phil Harvey,
>           },
>           SeeAlso = dc:subject,
>         },
>         {
>           Area =
>           {
>             W = 0.06, H = 0.09, X = 0.5, Y = 0.6,
>             Unit = normalized,
>           },
>           Description = this is a test|, what did you expect?,
>           Type = Focus,
>           FocusUsage = Evaluated|, Used,
>         }
>       ],
>     }

In this example, white space has been added in all allowed locations for demonstration purposes and to improve readability. Also, optional commas have been added after the last field of each structure. (Note that a comma may NOT be added after the last item in a list because this would be interpreted as an additional list item consisting of a zero-length string.)

## Examples

Here is an example of an advanced console session showing some commands which manipulate a complex list of structures (see the XMP-iptcExt tag documentation for details about the ArtworkOrObject structure tags used):

>     # 1. Create a XMP-iptcExt:ArtworkOrObject structure using flattened tags
>     > exiftool -artworktitle="a title" a.xmp
>         1 image files created

>     # -- Read back as flattened tags (-S is used just to shorten the output)
>     > exiftool -xmp-iptcext:all -S a.xmp
>     ArtworkTitle: a title

>     # -- Read back as a structure
>     > exiftool -xmp-iptcext:all -S -struct a.xmp
>     ArtworkOrObject: [{AOTitle=a title}]

>     # 2. Write another field to the structure as a flattened tag
>     > exiftool -artworkcreator=phil a.xmp
>         1 image files updated

>     # -- Note that the structure now has a new field
>     > exiftool -xmp-iptcext:all -S -struct a.xmp
>     ArtworkOrObject: [{AOCreator=[phil],AOTitle=a title}]

>     # 3. Add another creator using the "+=" operator
>     > exiftool -artworkcreator+=joe a.xmp
>         1 image files updated

>     # -- It was added to the first AOCreator list
>     > exiftool -xmp-iptcext:all -S -struct a.xmp
>     ArtworkOrObject: [{AOCreator=[phil,joe],AOTitle=a title}]

>     # 4. Add another artwork title
>     > exiftool -artworktitle+="another one" a.xmp
>         1 image files updated

>     # -- This created a new ArtworkOrObject structure in the list of structures
>     # (AOTitle itself is not a list, so a new structure must be created)
>     > exiftool -xmp-iptcext:all -S -struct a.xmp
>     ArtworkOrObject: [{AOCreator=[phil,joe],AOTitle=a title},{AOTitle=another one}]

>     # 5. Simply write a different title (do not add with "+=")
>     > exiftool -artworktitle="different" a.xmp
>         1 image files updated

>     # -- This deleted all existing AOTitle fields and wrote back only one
>     # (if the second ArtworkOrObject structure had contained more fields, they would have been
>     # preserved, and the second structure would still exist, but without an AOTitle field)
>     > exiftool -xmp-iptcext:all -S -struct a.xmp
>     ArtworkOrObject: [{AOCreator=[phil,joe],AOTitle=different}]

>     # 6. Add a completely new structure to the list
>     # (this is very difficult to do properly using flattened tags)
>     > exiftool -artworkorobject+="{aotitle=help,aocreator=[paul,ringo]}" a.xmp
>         1 image files updated

>     # -- The new structure was added with the specified fields
>     > exiftool -xmp-iptcext:all -S -struct a.xmp
>     ArtworkOrObject: [{AOCreator=[phil,joe],AOTitle=different},{AOCreator=[paul,ringo],AOTitle=help}]

>     # -- See how the relationships are lost when reading as flattened tags
>     > exiftool -xmp-iptcext:all -S a.xmp
>     ArtworkCreator: phil, joe, paul, ringo
>     ArtworkTitle: different, help

>     # 7. Delete all structures containing a specific field value
>     > exiftool -artworkorobject-="{AOCreator=phil}" a.xmp
>         1 image files updated

>     # -- The ArtworkOrObject list now contains only one structure
>     > exiftool -xmp-iptcext:all -S -struct a.xmp
>     ArtworkOrObject: [{AOCreator=[paul,ringo],AOTitle=help}]

## User-Defined Structures

User-defined XMP structure tags may be created via the ExifTool config file. See the NewXMPxxxStruct tag definition in the XMP-xxx examples of the sample config file for more details.

Last revised Jun 12, 2023

<-- Back to ExifTool home page