Skip to main content
Stephen Marsh
Community Expert
Community Expert
January 13, 2018
Answered

XMP Hierarchical Subject (lr:hierarchicalSubject)

  • January 13, 2018
  • 1 reply
  • 3335 views

Background to this post here: Re: Keywords and Subkeywords Display

I can’t script, however I can sometimes hack them. The more that I look into this, it is harder than I originally expected from say hacking a description to title script.

Would like to hack an existing Bridge script to copy the lr:hierarchicalSubject metadata to the standard subject/keyword metadata.

Source:

<lr:hierarchicalSubject>

            <rdf:Bag>

               <rdf:li>Corleone</rdf:li>

               <rdf:li>Corleone|Don Vito</rdf:li>

            </rdf:Bag>

</lr:hierarchicalSubject>

Result:

<dc:subject>

            <rdf:Bag>

               <rdf:li>Corleone</rdf:li>

               <rdf:li>Don Vito</rdf:li>

            </rdf:Bag>

</dc:subject>

Obviously will need to change the input string to an array/list. Only the content in green and blue would be required, the red content would not be required.

This is easy with ExifTool:

exiftool -r -subject= -keyword= -sep '|' -use MWG '-keywords<${XMP-lr:HierarchicalSubject}' 'pathToFile or Folder'

EDIT: I just found a clue here regarding the namespace:

Exiv2 - Image metadata library and tools

http://ns.adobe.com/lightroom/1.0/

hierarchicalSubject

This topic has been closed for replies.
Correct answer SuperMerlin

Here is a script for you to play with...

#target bridge;

   if( BridgeTalk.appName == "bridge" ) { 

hs = MenuElement.create("command", "Add hierarchicalSubject to Subject", "at the end of Tools");

}

hs.onSelect = function () {

var thumbs = app.document.selections;

if (ExternalObject.AdobeXMPScript == undefined)  ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");

for(var a =0;a<thumbs.length;a++){

var selectedFile =  new Thumbnail(thumbs);   

app.synchronousMode = true;

var xmp = new XMPMeta(selectedFile.synchronousMetadata.serialize());

var Keywords = getArrayItems(XMPConst.NS_DC,'subject');

var LRKeywords = getArrayItems("http://ns.adobe.com/lightroom/1.0/","hierarchicalSubject");

if(LRKeywords != ""){

LRKeywords = LRKeywords.toString().split("|");

for(var z in LRKeywords){ Keywords.push(LRKeywords);}

    }

Keywords = UniqueList(Keywords);

xmp.deleteProperty(XMPConst.NS_DC,"subject");

// Uncomment line below to DELETE hierarchicalSubject

//xmp.deleteProperty("http://ns.adobe.com/lightroom/1.0/","hierarchicalSubject");

for(var s in Keywords){

xmp.appendArrayItem(XMPConst.NS_DC, "subject", Keywords, 0,XMPConst.PROP_IS_ARRAY);

}

var newPacket = xmp.serialize(XMPConst.SERIALIZE_USE_COMPACT_FORMAT);

selectedFile.metadata = new Metadata(newPacket);

function getArrayItems(ns, prop){

var arrItem=[];

try{

var items = xmp.countArrayItems(ns, prop);

for(var i = 1;i <= items;i++){

arrItem.push(xmp.getArrayItem(ns, prop, i));

}

return arrItem;

}catch(e){alert(e +" Line: "+ e.line);}

    }

}

ExternalObject.AdobeXMPScript.unload();

ExternalObject.AdobeXMPScript = undefined;

function UniqueList(ArrayName){

var unduped = new Object;

for (var i = 0; i < ArrayName.length; i++) {  

unduped[ArrayName] = ArrayName;

};

var uniques = new Array;for (var k in unduped) {

   uniques.push(unduped);}

return uniques;

};

};


1 reply

SuperMerlin
Inspiring
January 13, 2018

Have you got an example file Stephen? Then I can take a look at it.

Stephen Marsh
Community Expert
Community Expert
January 13, 2018

Thanks for the reply SuperMerlin. It appears that tagging any photo with a Keyword (DC:Subject) entry in Bridge automatically adds both a legacy IPTC:Keyword and a Lightroom lr:hierarchicalSubject entry as well (at least with Bridge CC2018).

Here is a link to an image:

Dropbox - Don Vito Corleone (exiftool).jpg

SuperMerlin
SuperMerlinCorrect answer
Inspiring
January 13, 2018

Here is a script for you to play with...

#target bridge;

   if( BridgeTalk.appName == "bridge" ) { 

hs = MenuElement.create("command", "Add hierarchicalSubject to Subject", "at the end of Tools");

}

hs.onSelect = function () {

var thumbs = app.document.selections;

if (ExternalObject.AdobeXMPScript == undefined)  ExternalObject.AdobeXMPScript = new ExternalObject("lib:AdobeXMPScript");

for(var a =0;a<thumbs.length;a++){

var selectedFile =  new Thumbnail(thumbs);   

app.synchronousMode = true;

var xmp = new XMPMeta(selectedFile.synchronousMetadata.serialize());

var Keywords = getArrayItems(XMPConst.NS_DC,'subject');

var LRKeywords = getArrayItems("http://ns.adobe.com/lightroom/1.0/","hierarchicalSubject");

if(LRKeywords != ""){

LRKeywords = LRKeywords.toString().split("|");

for(var z in LRKeywords){ Keywords.push(LRKeywords);}

    }

Keywords = UniqueList(Keywords);

xmp.deleteProperty(XMPConst.NS_DC,"subject");

// Uncomment line below to DELETE hierarchicalSubject

//xmp.deleteProperty("http://ns.adobe.com/lightroom/1.0/","hierarchicalSubject");

for(var s in Keywords){

xmp.appendArrayItem(XMPConst.NS_DC, "subject", Keywords, 0,XMPConst.PROP_IS_ARRAY);

}

var newPacket = xmp.serialize(XMPConst.SERIALIZE_USE_COMPACT_FORMAT);

selectedFile.metadata = new Metadata(newPacket);

function getArrayItems(ns, prop){

var arrItem=[];

try{

var items = xmp.countArrayItems(ns, prop);

for(var i = 1;i <= items;i++){

arrItem.push(xmp.getArrayItem(ns, prop, i));

}

return arrItem;

}catch(e){alert(e +" Line: "+ e.line);}

    }

}

ExternalObject.AdobeXMPScript.unload();

ExternalObject.AdobeXMPScript = undefined;

function UniqueList(ArrayName){

var unduped = new Object;

for (var i = 0; i < ArrayName.length; i++) {  

unduped[ArrayName] = ArrayName;

};

var uniques = new Array;for (var k in unduped) {

   uniques.push(unduped);}

return uniques;

};

};