1 // =================================================================================================
2 // Copyright 2002-2008 Adobe Systems Incorporated
3 // All Rights Reserved.
4 //
5 // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
6 // of the Adobe license agreement accompanying it.
7 // =================================================================================================
8
9 /**
10 * Demonstrates how to use the iteration utility in the XMPCore component to walk through property trees.
11 */
12
13 #include <string>
14
15 // Must be defined to instantiate template classes
16 #define TXMP_STRING_TYPE std::string
17
18 // Must be defined to give access to XMPFiles
19 #define XMP_INCLUDE_XMPFILES 1
20
21 // Ensure XMP templates are instantiated
22 #include "XMP.incl_cpp"
23
24 // Provide access to the API
25 #include "XMP.hpp"
26
27 #include <iostream>
28
29 using namespace std;
30
31 // Provide some custom XMP
32 static const char * rdf =
33 "<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>"
34 " <rdf:Description rdf:about='' xmlns:xmpTest='http://ns.adobe.com/xmpTest/'>"
35 ""
36 " <xmpTest:MySimpleProp rdf:parseType='Resource'>"
37 " <rdf:value>A Value</rdf:value>"
38 " <xmpTest:MyQual>Qual Value</xmpTest:MyQual>"
39 " </xmpTest:MySimpleProp>"
40 ""
41 " <xmpTest:MyTopStruct rdf:parseType='Resource'>"
42 " <xmpTest:MySecondStruct rdf:parseType='Resource'>"
43 " <xmpTest:MyThirdStruct rdf:parseType='Resource'>"
44 " <xmpTest:MyThirdStructField>Field Value 3</xmpTest:MyThirdStructField>"
45 " </xmpTest:MyThirdStruct>"
46 " <xmpTest:MySecondStructField>Field Value 2</xmpTest:MySecondStructField>"
47 " </xmpTest:MySecondStruct>"
48 " <xmpTest:MyTopStructField>Field Value 1</xmpTest:MyTopStructField>"
49 " </xmpTest:MyTopStruct>"
50
51 " <xmpTest:MyArrayWithNestedArray>"
52 " <rdf:Bag>"
53 " <rdf:li>"
54 " <rdf:Seq>"
55 " <rdf:li>Item 1</rdf:li>"
56 " <rdf:li>Item 2</rdf:li>"
57 " </rdf:Seq>"
58 " </rdf:li>"
59 " </rdf:Bag>"
60 " </xmpTest:MyArrayWithNestedArray>"
61
62 " <xmpTest:MyArrayWithStructures>"
63 " <rdf:Seq>"
64 " <rdf:li rdf:parseType='Resource'>"
65 " <rdf:value>Field Value 1</rdf:value>"
66 " <xmpTest:FirstQual>Qual Value 1</xmpTest:FirstQual>"
67 " <xmpTest:SecondQual>Qual Value 2</xmpTest:SecondQual>"
68 " </rdf:li>"
69 " <rdf:li rdf:parseType='Resource'>"
70 " <rdf:value>Field Value 2</rdf:value>"
71 " <xmpTest:FirstQual>Qual Value 3</xmpTest:FirstQual>"
72 " <xmpTest:SecondQual>Qual Value 4</xmpTest:SecondQual>"
73 " </rdf:li>"
74 " </rdf:Seq>"
75 " </xmpTest:MyArrayWithStructures>"
76 ""
77 " <xmpTest:MyStructureWithArray rdf:parseType='Resource'>"
78 " <xmpTest:NestedArray>"
79 " <rdf:Bag>"
80 " <rdf:li>Item 3</rdf:li>"
81 " <rdf:li>Item 4</rdf:li>"
82 " <rdf:li>Item 5</rdf:li>"
83 " <rdf:li>Item 6</rdf:li>"
84 " </rdf:Bag>"
85 " </xmpTest:NestedArray>"
86 " <xmpTest:NestedArray2>"
87 " <rdf:Bag>"
88 " <rdf:li>Item 66</rdf:li>"
89 " <rdf:li>Item 46</rdf:li>"
90 " <rdf:li>Item 56</rdf:li>"
91 " <rdf:li>Item 66</rdf:li>"
92 " </rdf:Bag>"
93 " </xmpTest:NestedArray2>"
94 " </xmpTest:MyStructureWithArray>"
95 ""
96 " </rdf:Description>"
97 "</rdf:RDF>";
98
99 // The namespace to be used. This will be automatically registered
100 // when the RDF is parsed.
101 const XMP_StringPtr kXMP_NS_SDK = "http://ns.adobe.com/xmpTest/";
102
103 /**
104 * Reads some metadata from a file and appends some custom XMP to it. Then does several
105 * iterations, using various iterators. Each iteration is displayed in the console window.
106 */
main()107 int main()
108 {
109 if(SXMPMeta::Initialize())
110 {
111 SXMPFiles::Initialize();
112
113 bool ok;
114 SXMPFiles myFile;
115
116 XMP_OptionBits opts = kXMPFiles_OpenForRead | kXMPFiles_OpenUseSmartHandler;
117 ok = myFile.OpenFile("../../../testfiles/Image1.jpg", kXMP_UnknownFile, opts);
118 if(ok)
119 {
120 SXMPMeta xmp;
121 myFile.GetXMP(&xmp);
122
123 // Add some custom metadata to the XMP object
124 SXMPMeta custXMP(rdf, (XMP_StringLen) strlen(rdf));
125 SXMPUtils::AppendProperties(custXMP, &xmp);
126
127 // Store any details from the iter.Next() call
128 string schemaNS, propPath, propVal;
129
130 // Only visit the immediate children that are leaf properties of the Dublin Core schema
131 SXMPIterator dcLeafIter(xmp, kXMP_NS_DC, (kXMP_IterJustChildren | kXMP_IterJustLeafNodes));
132 while(dcLeafIter.Next(&schemaNS, &propPath, &propVal))
133 {
134 cout << schemaNS << " " << propPath << " = " << propVal << endl;
135 }
136
137 cout << "----------------------------------" << endl;
138
139 // Visit one property from the XMP Basic schema
140 SXMPIterator xmpKeywordsIter(xmp, kXMP_NS_XMP, "Keywords", kXMP_IterJustLeafNodes);
141 while(xmpKeywordsIter.Next(&schemaNS, &propPath, &propVal))
142 {
143 cout << schemaNS << " " << propPath << " = " << propVal << endl;
144 }
145
146 cout << "----------------------------------" << endl;
147
148 // Visit the Dublin Core schema, omit any quailifiers and only
149 // show the leaf properties
150 SXMPIterator dcIter(xmp, kXMP_NS_DC, (kXMP_IterOmitQualifiers | kXMP_IterJustLeafNodes));
151 while(dcIter.Next(&schemaNS, &propPath, &propVal))
152 {
153 cout << schemaNS << " " << propPath << " = " << propVal << endl;
154 }
155
156 cout << "----------------------------------" << endl;
157
158 // Visit the Dublin Core schema, omit any quailifiers,
159 // show the leaf properties but only return the leaf name and not the full path
160 SXMPIterator dcIter2(xmp, kXMP_NS_DC, (kXMP_IterOmitQualifiers | kXMP_IterJustLeafNodes | kXMP_IterJustLeafName));
161 while(dcIter2.Next(&schemaNS, &propPath, &propVal))
162 {
163 cout << schemaNS << " " << propPath << " = " << propVal << endl;
164 }
165
166 cout << "----------------------------------" << endl;
167
168 // Iterate over a single namespace. Show all properties within
169 // the Photoshop schema
170 SXMPIterator exifIter(xmp, kXMP_NS_Photoshop);
171 while(exifIter.Next(&schemaNS, &propPath, &propVal))
172 {
173 cout << schemaNS << " " << propPath << " = " << propVal << endl;
174 }
175
176 cout << "----------------------------------" << endl;
177
178 // Just visit the leaf nodes of EXIF properties. That is just
179 // properties that may have values.
180 SXMPIterator exifLeafIter(xmp, kXMP_NS_EXIF, kXMP_IterJustLeafNodes);
181 while(exifLeafIter.Next(&schemaNS, &propPath, &propVal))
182 {
183 cout << schemaNS << " " << propPath << " = " << propVal << endl;
184 }
185
186 cout << "----------------------------------" << endl;
187
188 // Iterate over all properties but skip the EXIF schema and skip the custom schema
189 // and continue visiting nodes
190 SXMPIterator skipExifIter (xmp);
191 while(skipExifIter.Next(&schemaNS, &propPath, &propVal))
192 {
193 if(schemaNS == kXMP_NS_EXIF || schemaNS == kXMP_NS_SDK)
194 {
195 skipExifIter.Skip(kXMP_IterSkipSubtree);
196 }
197 else
198 {
199 cout << schemaNS << " " << propPath << " = " << propVal << endl;
200 }
201 }
202
203 cout << "----------------------------------" << endl;
204
205 // Iterate over all properties but skip the EXIF schema
206 // and any remaining siblings of the current node.
207 SXMPIterator stopAfterExifIter ( xmp );
208 while(stopAfterExifIter.Next(&schemaNS, &propPath, &propVal))
209 {
210 if(schemaNS == kXMP_NS_EXIF || schemaNS == kXMP_NS_SDK)
211 {
212 stopAfterExifIter.Skip(kXMP_IterSkipSiblings);
213 }
214 else
215 {
216 cout << schemaNS << " " << propPath << " = " << propVal << endl;
217 }
218 }
219
220 cout << "----------------------------------" << endl;
221
222 //////////////////////////////////////////////////////////////////////////////////////
223
224 // Iterate over the custom XMP
225
226 // Visit the immediate children of this node.
227 // No qualifiers are visisted as they are below the property being visisted.
228 SXMPIterator justChildrenIter(xmp, kXMP_NS_SDK, kXMP_IterJustChildren);
229 while(justChildrenIter.Next(&schemaNS, &propPath, &propVal))
230 {
231 cout << propPath << " = " << propVal << endl;
232 }
233
234 cout << "----------------------------------" << endl;
235
236 // Visit the immediate children of this node but only those that may have values.
237 // No qualifiers are visisted as they are below the property being visisted.
238 SXMPIterator justChildrenAndLeafIter(xmp, kXMP_NS_SDK, (kXMP_IterJustChildren | kXMP_IterJustLeafNodes));
239 while(justChildrenAndLeafIter.Next(&schemaNS, &propPath, &propVal))
240 {
241 cout << propPath << " = " << propVal << endl;
242 }
243
244 cout << "----------------------------------" << endl;
245
246 // Visit the leaf nodes of TopStructProperty
247 SXMPIterator myTopStructIter(xmp, kXMP_NS_SDK, "MyTopStruct", kXMP_IterJustLeafNodes);
248 while(myTopStructIter.Next(&schemaNS, &propPath, &propVal))
249 {
250 cout << propPath << " = " << propVal << endl;
251 }
252
253 cout << "----------------------------------" << endl;
254
255 // Visit the leaf nodes of the TopStructProperty but only return the names for
256 // the leaf components and not the full path
257 SXMPIterator xmyTopStructIterShortNames(xmp, kXMP_NS_SDK, "MyTopStruct", (kXMP_IterJustLeafNodes | kXMP_IterJustLeafName));
258 while(xmyTopStructIterShortNames.Next(&schemaNS, &propPath, &propVal))
259 {
260 cout << propPath << " = " << propVal << endl;
261 }
262
263 cout << "----------------------------------" << endl;
264
265 // Visit a property and all of the qualifiers
266 SXMPIterator iterArrayProp (xmp, kXMP_NS_SDK, "ArrayWithStructures", kXMP_IterJustLeafNodes );
267 while(iterArrayProp.Next(&schemaNS, &propPath, &propVal))
268 {
269 cout << propPath << " = " << propVal << endl;
270 }
271
272 cout << "----------------------------------" << endl;
273
274 // Visit a property and omit all of the qualifiers
275 SXMPIterator iterArrayPropNoQual (xmp, kXMP_NS_SDK, "ArrayWithStructures", (kXMP_IterJustLeafNodes | kXMP_IterOmitQualifiers));
276 while(iterArrayPropNoQual.Next(&schemaNS, &propPath, &propVal))
277 {
278 cout << propPath << " = " << propVal << endl;
279 }
280
281 cout << "----------------------------------" << endl;
282
283 // Skip a subtree and continue onwards. Once 'Item 4' is found then the we can skip all of the
284 // siblings of the current node. If the the current node were a top level node the iteration
285 // would be complete as all siblings would be skipped. However, when 'Item 4' is found the current
286 // node is not at the top level so there are other nodes further up the tree that still need to be
287 // visited.
288 SXMPIterator skipIter (xmp, kXMP_NS_SDK, (kXMP_IterJustLeafNodes | kXMP_IterOmitQualifiers | kXMP_IterJustLeafName));
289 while(skipIter.Next(&schemaNS, &propPath, &propVal))
290 {
291 if(propVal == "Item 4")
292 {
293 skipIter.Skip(kXMP_IterSkipSiblings);
294 }
295 else
296 {
297 cout << schemaNS << " " << propPath << " = " << propVal << endl;
298 }
299 }
300
301 /*
302 // Visit all properties and qualifiers
303 SXMPIterator allPropsIter(xmp);
304 while(allPropsIter.Next(&schemaNS, &propPath, &propVal))
305 {
306 cout << schemaNS << " " << propPath << " = " << propVal << endl;
307 }
308 */
309 }
310
311 }
312
313 SXMPFiles::Terminate();
314 SXMPMeta::Terminate();
315
316 return 0;
317 }
318
319