source: 1dwg/branches/v1.1/IgorPro/cansasXML.ipf @ 306

Last change on this file since 306 was 306, checked in by prjemian, 9 years ago

fixes #28

  • Property svn:keywords set to Date Revision Author HeadURL Id
File size: 38.3 KB
Line 
1#pragma rtGlobals=1             // rtGlobals=3 requires IgorPro 6.3+
2#pragma version=1.12
3
4// file:        cansasXML.ipf
5// author:      Pete R. Jemian <jemian@anl.gov>
6// SVN date:    $Date$
7// SVN rev.:    $Revision$
8// SVN URL:     $HeadURL$
9// SVN ID:      $Id$
10// purpose:  implement an IgorPro file reader to read the canSAS 1-D reduced SAS data in XML files
11//                      adhering to either the cansas1d/1.0 or cansas1d/1.1 standards
12// readme:    http://www.cansas.org/formats/canSAS1d/1.1/doc/binding-igorpro.html
13// URL: http://www.cansas.org/formats/canSAS1d/1.1/doc/
14//
15// requires:    IgorPro (http://www.wavemetrics.com/)
16//                              XMLutils - XOP (http://www.igorexchange.com/project/XMLutils)
17// provides:  CS_XmlReader(String fileName)
18//                              all other functions in this file should not be relied upon
19
20//  ================  ================  =================
21//  #pragma version   canSAS1d version  namespace
22//  ================  ================  =================
23//  1.12              v1.1              urn:cansas1d:1.1
24//  1.11              v1.0              cansas1d/1.0
25//  ================  ================  =================
26
27
28// ==================================================================
29// CS_XmlReader("../examples/bimodal-test1.xml")
30// CS_XmlReader("../examples/1998spheres.xml")
31// CS_XmlReader("../examples/xg009036_001.xml")
32// CS_XmlReader("../examples/s81-polyurea.xml")
33// CS_XmlReader("../examples/cs_af1410.xml")
34//  testCollette();  prjTest_cansas1d()
35// ==================================================================
36
37
38#if( ! Exists("XmlOpenFile") )
39        // BEFORE we do anything else, check that XMLutils XOP is available.
40        // No XMLutils XOP: provide dummy function so that IgorPro can compile dependent support code
41
42        FUNCTION CS_XmlReader(fileName)
43            String fileName
44                String msg
45                msg = "XML function provided by XMLutils XOP is not available,"
46                msg += " get the XOP from : http://www.igorexchange.com/project/XMLutils"
47                msg += " (see http://www.cansas.org/formats/canSAS1d/1.1/doc/binding-igorpro.html for details)"
48            Abort  msg
49            RETURN(-6)
50        END
51
52#else   // if( Exists("XmlOpenFile") )
53
54FUNCTION CS_XmlReader(fileName)
55        //
56        // open a canSAS 1-D reduced SAS XML data file
57        //      returns:
58        //              0 : successful
59        //              -1: XML file not found
60        //              -2: root element is not <SASroot> with valid canSAS namespace
61        //              -3: <SASroot> version  is not 1.0 or 1.1
62        //              -4: no <SASentry> elements
63        //              -5: XMLutils XOP needs upgrade
64        //              -6: XMLutils XOP not found
65        //
66        STRING fileName
67        STRING origFolder
68        STRING workingFolder = "root:Packages:CS_XMLreader"
69        VARIABLE returnCode
70
71
72        //
73        // set up a work folder within root:Packages
74        // Clear out any progress/results from previous activities
75        //
76        origFolder = GetDataFolder(1)
77        SetDataFolder root:                                     // start in the root data folder
78        NewDataFolder/O  root:Packages          // good practice
79        KillDataFolder/Z  $workingFolder                // clear out any previous work
80        NewDataFolder/O/S  $workingFolder       // Do all our work in root:XMLreader
81
82        //
83        // Try to open the named XML file (clean-up and return if failure)
84        //
85        VARIABLE fileID
86        STRING/G errorMsg, xmlFile
87        xmlFile = fileName
88        fileID = XmlOpenFile(fileName)                  // open and parse the XMLfile
89        IF ( fileID < 0 )
90                SWITCH(fileID)                                  // fileID holds the return code; check it
91                        CASE -1:
92                                errorMsg = fileName + ": failed to parse XML"
93                        BREAK
94                        CASE -2:
95                                errorMsg = fileName + " either not found or cannot be opened for reading"
96                        BREAK
97                ENDSWITCH
98                PRINT errorMsg
99                SetDataFolder $origFolder
100                RETURN(-1)                                              // could not find file
101        ENDIF
102
103        //
104        //      test to see if XMLutils has the needed upgrade
105        //
106        XMLlistXpath(fileID, "/*", "") 
107        IF ( EXISTS( "M_listXPath" ) == 0 )
108                XmlCloseFile(fileID,0)
109                errorMsg = "XMLutils needs an upgrade:  http://www.igorexchange.com/project/XMLutils"
110                PRINT errorMsg
111                SetDataFolder $origFolder
112                RETURN(-5)                                              // XOPutils needs an upgrade
113        ENDIF
114        WAVE/T  M_listXPath
115
116        // check for canSAS namespace string, returns "" if not valid or not found
117        STRING/G ns = CS_getDefaultNamespace(fileID)
118        IF (strlen(ns) == 0 )
119                XmlCloseFile(fileID,0)
120                errorMsg = "root element is not <SASroot> with valid canSAS namespace"
121                PRINT errorMsg
122                SetDataFolder $origFolder
123                RETURN(-2)                                              // root element is not <SASroot> with valid canSAS namespace
124        ENDIF
125        STRING/G nsPre = "cs:"
126        STRING/G nsStr = "cs=" + ns
127
128        SVAR nsPre = root:Packages:CS_XMLreader:nsPre
129        SVAR nsStr = root:Packages:CS_XMLreader:nsStr
130       
131        STRSWITCH(ns)   
132        CASE "cansas1d/1.0":                                                    // version 1.0 of the canSAS 1-D reduced SAS data standard
133        CASE "urn:cansas1d:1.1":                                                // version 1.1 of the canSAS 1-D reduced SAS data standard
134                PRINT fileName, "\t\t identified as: " + ns + " XML file"
135                returnCode = CS_1i_parseXml(fileID)                     //  This is where the action happens!
136                IF (returnCode != 0)
137                        IF (strlen(errorMsg) == 0)
138                                errorMsg = "error while parsing the XML"
139                        ENDIF
140                        PRINT errorMsg
141                        XmlCloseFile(fileID,0)
142                        SetDataFolder $origFolder
143                        RETURN(returnCode)                      // error while parsing the XML
144                ENDIF
145                BREAK
146        CASE "cansas1d/2.0a":                                           // unsupported
147        DEFAULT:                                                        // optional default expression executed
148                errorMsg = fileName + ": <SASroot>, namespace (" + ns + ") is not supported"
149                PRINT errorMsg
150                XmlCloseFile(fileID,0)
151                SetDataFolder $origFolder
152                RETURN(-3)                                              // attribute list must include version="1.0"
153        ENDSWITCH
154
155        XmlCloseFile(fileID,0)                                  // now close the file, without saving
156        fileID = -1
157
158        SetDataFolder root:Packages:CS_XMLreader
159        KillWaves/Z M_listXPath, SASentryList
160        SetDataFolder $origFolder
161        RETURN(0)                                                       // execution finished OK
162END
163
164FUNCTION/S CS_getDefaultNamespace(fileID)
165        // Test here (by guessing) for the various known namespaces.
166        // Return the one found in the "schemaLocation" attribute
167        // since the XMLutils XOP does not provide any xmlns attributes.
168        // It is possible to call XMLelemList and get the namespace directly
169        // but that call can be expensive (time) when there are lots of elements.
170        VARIABLE fileID
171        STRING ns = "", thisLocation
172        VARIABLE i, item
173        MAKE/T/N=(2)/O nsList           // list of all possible namespaces
174        nsList[0] = "cansas1d/1.0"              // first version of canSAS 1-D reduced SAS
175        nsList[1] = "urn:cansas1d:1.1"  // second version of canSAS 1-D reduced SAS
176
177        FOR (item = 0; item < DimSize(nsList, 0); item += 1)            // loop over all possible namespaces
178                XMLlistAttr(fileID, "/cs:SASroot", "cs="+nsList[item])
179                WAVE/T M_listAttr
180                FOR (i = 0; i < DimSize(M_listAttr,0); i+=1)                    // loop over all available attributes
181                        // Expect the required canSAS XML header (will fail if "schemalocation" is not found)
182                        IF ( CmpStr(  LowerStr(M_listAttr[i][1]),  LowerStr("schemaLocation") ) == 0 )
183                                thisLocation = TrimWS(M_listAttr[i][2])
184                                IF ( StringMatch(thisLocation, nsList[item] + "*") )
185                                        ns = nsList[item]
186                                        BREAK           // found it!
187                                ENDIF
188                        ENDIF
189                ENDFOR
190                IF (strlen(ns))
191                        BREAK           // found it!
192                ENDIF
193        ENDFOR
194
195        KillWaves/Z nsList, M_listAttr
196        RETURN ns
197END
198
199// ==================================================================
200
201FUNCTION CS_1i_parseXml(fileID)
202        VARIABLE fileID
203        SVAR errorMsg, xmlFile
204        STRING/G Title, Title_folder
205        VARIABLE i, j, index, SASdata_index, returnCode = 0
206
207        SVAR nsPre = root:Packages:CS_XMLreader:nsPre
208        SVAR nsStr = root:Packages:CS_XMLreader:nsStr
209
210        // locate all the SASentry elements
211        //      assume nsPre = "cs" otherwise
212        // "/"+nsPre+":SASroot//"+nsPre+":SASentry"
213        XmlListXpath(fileID, "/cs:SASroot//cs:SASentry", nsStr)
214        WAVE/T  M_listXPath
215        STRING          SASentryPath
216        DUPLICATE/O/T   M_listXPath, SASentryList
217
218        FOR (i=0; i < DimSize(SASentryList, 0); i += 1)
219                SASentryPath = "/cs:SASroot/cs:SASentry["+num2str(i+1)+"]"
220                SetDataFolder root:Packages:CS_XMLreader
221               
222                title =  CS_1i_locateTitle(fileID, SASentryPath)
223                Title_folder = CS_cleanFolderName(Title)
224                NewDataFolder/O/S  $Title_folder
225
226                XmlListXpath(fileID, SASentryPath + "//cs:SASdata", nsStr)
227                WAVE/T  M_listXPath
228                IF ( DimSize(M_listXPath, 0) == 1)
229                        CS_1i_getOneSASdata(fileID, Title, SASentryPath+"/cs:SASdata")
230                        CS_1i_collectMetadata(fileID, SASentryPath)
231                ELSE
232                        FOR (j = 0; j < DimSize(M_listXPath, 0); j += 1)
233                                // Could make this new behavior optional
234                                STRING SASdata_item = "SASdata_" + num2str(j)
235                                STRING SASdata_node = SASentryPath+"/cs:SASdata["+num2str(j+1)+"]"
236                                // Preferred name obtained from the SASentry/SASdata/@name attribute, if present
237                                STRING SASdata_name = XMLstrFmXpath(fileID,  SASdata_node + "/@name", nsStr, "")
238                                IF (strlen(SASdata_name) == 0)
239                                        IF (DimSize(M_listXPath, 0) == 1)
240                                                // Alternative if only one SASdata block is to use the SASentry/Title
241                                                SASdata_name = XMLstrFmXpath(fileID,  SASentryPath+"/cs:Title", nsStr, "")
242                                        ELSE
243                                                // the original behavior: SASdata_0, SASdata_1, ...
244                                                SASdata_name = SASdata_item
245                                        ENDIF
246                                        // the original behavior: SASdata_0, SASdata_1, ...
247                                        SASdata_name = SASdata_item
248                                ENDIF
249                                STRING SASdataFolder = CS_cleanFolderName(SASdata_name)
250                                NewDataFolder/O/S  $SASdataFolder
251                                CS_1i_getOneSASdata(fileID, Title, SASdata_node)
252                                CS_1i_collectMetadata(fileID, SASentryPath)
253                                SetDataFolder ::                        // back up to parent directory
254                        ENDFOR
255                ENDIF
256
257                // TODO: process any transmission spectra
258                STRING/G ns = CS_getDefaultNamespace(fileID)
259                IF (cmpstr(ns,  "urn:cansas1d:1.1") == 0)
260                        XmlListXpath(fileID, SASentryPath + "//cs:SAStransmission_spectrum", nsStr)
261                        WAVE/T  M_listXPath
262                        print "Searching for SAStransmission_spectrum groups"
263                        print DimSize(M_listXPath, 0) , M_listXPath
264                        // ...
265                ENDIF
266               
267                KillWaves/Z M_listXPath
268        ENDFOR
269
270        SetDataFolder root:Packages:CS_XMLreader
271        KillWaves/Z M_listXPath, SASentryList
272        RETURN(returnCode)
273END
274
275// ==================================================================
276
277FUNCTION/S CS_cleanFolderName(proposal)
278        STRING proposal
279        STRING result
280        result = CleanupName(proposal, 0)
281        IF ( CheckName(result, 11) != 0 )
282                result = UniqueName(result, 11, 0)
283        ENDIF
284        RETURN result
285END
286
287// ==================================================================
288
289FUNCTION CS_1i_getOneSASdata(fileID, Title, SASdataPath)
290        VARIABLE fileID
291        STRING Title, SASdataPath
292        SVAR nsPre = root:Packages:CS_XMLreader:nsPre
293        SVAR nsStr = root:Packages:CS_XMLreader:nsStr
294        VARIABLE i
295        STRING SASdata_name, suffix = ""
296
297        //grab the data and put it in the working data folder
298        CS_1i_GetReducedSASdata(fileID, SASdataPath)
299
300        //start the metadata
301        MAKE/O/T/N=(0,2) metadata
302
303        SVAR xmlFile = root:Packages:CS_XMLreader:xmlFile
304        CS_appendMetaData(fileID, "xmlFile", "", xmlFile)
305
306        SVAR ns = root:Packages:CS_XMLreader:ns
307        CS_appendMetaData(fileID, "namespace", "", ns)
308        CS_appendMetaData(fileID, "Title", "", Title)
309       
310        XmlListXpath(fileID, SASdataPath + "/..//cs:Run", nsStr)
311        WAVE/T  M_listXPath
312        FOR (i=0; i < DimSize(M_listXPath, 0); i += 1)
313                IF ( DimSize(M_listXPath, 0) > 1 )
314                        suffix = "_" + num2str(i)
315                ENDIF
316                CS_appendMetaData(fileID, "Run" + suffix,  SASdataPath + "/../cs:Run["+num2str(i+1)+"]", "")
317                CS_appendMetaData(fileID, "Run/@name" + suffix,  SASdataPath + "/../cs:Run["+num2str(i+1)+"]/@name", "")
318        ENDFOR
319
320        SASdata_name = TrimWS(XMLstrFmXpath(fileID,  SASdataPath + "/@name", nsStr, ""))
321        CS_appendMetaData(fileID, "SASdata/@name", "", SASdata_name)
322
323        KillWaves/Z M_listXPath
324END
325
326// ==================================================================
327
328FUNCTION CS_1i_getOneVector(file,prefix,XML_name,Igor_name)
329        VARIABLE file
330        STRING prefix,XML_name,Igor_name
331        SVAR nsPre = root:Packages:CS_XMLreader:nsPre
332        SVAR nsStr = root:Packages:CS_XMLreader:nsStr
333
334        XmlWaveFmXpath(file,prefix+XML_name,nsStr,"")                   //this loads ALL the vector's nodes at the same time
335        WAVE/T M_xmlcontent
336        WAVE/T W_xmlContentNodes
337        IF (DimSize(M_xmlcontent, 0))                   // test to see if the nodes exist.  not strictly necessary if you know the nodes are there
338                IF (DimSize(M_xmlcontent,1)>DimSize(M_xmlcontent,0))    //if you're not in vector mode
339                        MatrixTranspose M_xmlcontent
340                ENDIF
341                MAKE/O/D/N=(DimSize(M_xmlcontent, 0)) $Igor_name
342                WAVE vect = $Igor_name
343                vect=str2num(M_xmlcontent)
344        ENDIF
345        KILLWAVES/Z M_xmlcontent, W_xmlContentNodes
346END
347
348// ==================================================================
349
350FUNCTION CS_1i_GetReducedSASdata(fileID, SASdataPath)
351        VARIABLE fileID
352        STRING SASdataPath
353        SVAR nsPre = root:Packages:CS_XMLreader:nsPre
354        SVAR nsStr = root:Packages:CS_XMLreader:nsStr
355        STRING prefix = ""
356        VARIABLE pos
357
358        VARIABLE cansasStrict = 1               // !!!software developer's choice!!!
359        IF (cansasStrict)               // only get known canSAS data vectors
360                prefix = SASdataPath + "//cs:"
361                // load ALL nodes of each vector (if exists) at the same time
362                CS_1i_getOneVector(fileID, prefix, "Q",                 "Qsas")
363                CS_1i_getOneVector(fileID, prefix, "I",                 "Isas")
364                CS_1i_getOneVector(fileID, prefix, "Idev",              "Idev")
365                CS_1i_getOneVector(fileID, prefix, "Qdev",              "Qdev")
366                CS_1i_getOneVector(fileID, prefix, "dQw",       "dQw")
367                CS_1i_getOneVector(fileID, prefix, "dQl",               "dQl")
368                CS_1i_getOneVector(fileID, prefix, "Qmean",     "Qmean")
369                CS_1i_getOneVector(fileID, prefix, "Shadowfactor",      "Shadowfactor")
370                // check them for common length
371        ELSE                            // search for _ANY_ data vectors
372                // find the names of all the data columns and load them as vectors
373                // this gets tricky if we want to avoid namespace references
374                XmlListXpath(fileID, SASdataPath+"//cs:Idata[1]/*", nsStr)
375                WAVE/T M_listXPath
376                STRING xmlElement, xPathStr
377                STRING igorWave
378                VARIABLE j
379                FOR (j = 0; j < DimSize(M_listXPath, 0); j += 1)        // loop over all columns in SASdata/Idata[1]
380                        xmlElement = M_listXPath[j][1]
381                        STRSWITCH(xmlElement)
382                                CASE "Q":               // IgorPro does not allow a variable named Q
383                                CASE "I":                       // or I
384                                        igorWave = xmlElement + "sas"
385                                        BREAK
386                                DEFAULT:
387                                        igorWave = xmlElement           // can we trust this one?
388                        ENDSWITCH
389                        //
390//                      // This will need some work to support foreign namespaces here
391//                      //
392//                      //
393//                      xPathStr = M_listXPath[j][0]                                                    // clear name reference
394//                      pos = strsearch(xPathStr, "/", Inf, 3)                                  // peel off the tail of the string and reform
395//                      xmlElement = xPathStr[pos,Inf]                                          // find last element on the path
396//                      prefix = xPathStr[0, pos-1-4]+"/*"                                              // ALL Idata elements
397//                      CS_1i_getOneVector(fileID,prefix, xmlElement, igorWave)         // loads ALL rows (Idata) of the column at the same time
398                        //
399                        //  Could there be a problem with a foreign namespace here?
400                        prefix = SASdataPath+"//cs:Idata"                                               // ALL Idata elements
401                        xmlElement = "cs:" + M_listXPath[j][1]                                  // just this column
402                        CS_1i_getOneVector(fileID,prefix, xmlElement, igorWave)         // loads ALL rows (Idata) of the column at the same time
403                ENDFOR
404                // check them for common length
405        ENDIF
406 
407        //get rid of any mess
408        KILLWAVES/z M_listXPath
409END
410
411// ==================================================================
412
413FUNCTION CS_1i_collectMetadata(fileID, sasEntryPath)
414        VARIABLE fileID
415        STRING sasEntryPath
416        VARIABLE i, j
417        WAVE/T metadata
418        STRING suffix = "", preMeta = "", preXpath = ""
419        STRING value, detailsPath, detectorPath, notePath
420
421        SVAR nsPre = root:Packages:CS_XMLreader:nsPre
422        SVAR nsStr = root:Packages:CS_XMLreader:nsStr
423
424        // collect some metadata
425        // first, fill a table with keywords, and XPath locations, 3rd column will be values
426
427        // handle most <SASsample> fields
428        CS_appendMetaData(fileID, "SASsample/@name",                            sasEntryPath + "/cs:SASsample/@name", "")
429        CS_appendMetaData(fileID, "SASsample/ID",                                       sasEntryPath + "/cs:SASsample/cs:ID", "")
430        CS_appendMetaData(fileID, "SASsample/thickness",                                sasEntryPath + "/cs:SASsample/cs:thickness", "")
431        CS_appendMetaData(fileID, "SASsample/thickness/@unit",                  sasEntryPath + "/cs:SASsample/cs:thickness/@unit", "")
432        CS_appendMetaData(fileID, "SASsample/transmission",                     sasEntryPath + "/cs:SASsample/cs:transmission", "")
433        CS_appendMetaData(fileID, "SASsample/temperature",                      sasEntryPath + "/cs:SASsample/cs:temperature", "")
434        CS_appendMetaData(fileID, "SASsample/temperature/@unit",           sasEntryPath + "/cs:SASsample/cs:temperature/@unit", "")
435        CS_appendMetaData(fileID, "SASsample/position/x",                          sasEntryPath + "/cs:SASsample/cs:position/cs:x", "")
436        CS_appendMetaData(fileID, "SASsample/position/x/@unit",            sasEntryPath + "/cs:SASsample/cs:position/cs:x/@unit", "")
437        CS_appendMetaData(fileID, "SASsample/position/y",                          sasEntryPath + "/cs:SASsample/cs:position/cs:y", "")
438        CS_appendMetaData(fileID, "SASsample/position/y/@unit",            sasEntryPath + "/cs:SASsample/cs:position/cs:y/@unit", "")
439        CS_appendMetaData(fileID, "SASsample/position/z",                          sasEntryPath + "/cs:SASsample/cs:position/cs:z", "")
440        CS_appendMetaData(fileID, "SASsample/position/z/@unit",            sasEntryPath + "/cs:SASsample/cs:position/cs:z/@unit", "")
441        CS_appendMetaData(fileID, "SASsample/orientation/roll",                    sasEntryPath + "/cs:SASsample/cs:orientation/cs:roll", "")
442        CS_appendMetaData(fileID, "SASsample/orientation/roll/@unit",      sasEntryPath + "/cs:SASsample/cs:orientation/cs:roll/@unit", "")
443        CS_appendMetaData(fileID, "SASsample/orientation/pitch",           sasEntryPath + "/cs:SASsample/cs:orientation/cs:pitch", "")
444        CS_appendMetaData(fileID, "SASsample/orientation/pitch/@unit",     sasEntryPath + "/cs:SASsample/cs:orientation/cs:pitch/@unit", "")
445        CS_appendMetaData(fileID, "SASsample/orientation/yaw",                     sasEntryPath + "/cs:SASsample/cs:orientation/cs:yaw", "")
446        CS_appendMetaData(fileID, "SASsample/orientation/yaw/@unit",       sasEntryPath + "/cs:SASsample/cs:orientation/cs:yaw/@unit", "")
447        // <SASsample><details> might appear multiple times, too!
448        XmlListXpath(fileID, sasEntryPath+"/cs:SASsample//cs:details", nsStr)   //output: M_listXPath
449        WAVE/T  M_listXPath
450        DUPLICATE/O/T   M_listXPath, detailsList
451        suffix = ""
452        FOR (i = 0; i < DimSize(detailsList, 0); i += 1)
453                IF (DimSize(detailsList, 0) > 1)
454                        suffix = "_" + num2str(i)
455                ENDIF
456                detailsPath = sasEntryPath+"/cs:SASsample/cs:details["+num2str(i+1)+"]"
457                CS_appendMetaData(fileID, "SASsample/details"+suffix+"/@name",  detailsPath + "/@name", "")
458                CS_appendMetaData(fileID, "SASsample/details"+suffix,           detailsPath, "")
459        ENDFOR
460
461
462        // <SASinstrument>
463        CS_appendMetaData(fileID, "SASinstrument/name",         sasEntryPath + "/cs:SASinstrument/cs:name", "")
464        CS_appendMetaData(fileID, "SASinstrument/@name",        sasEntryPath + "/cs:SASinstrument/@name", "")
465
466        // <SASinstrument><SASsource>
467        preMeta = "SASinstrument/SASsource"
468        preXpath = sasEntryPath + "/cs:SASinstrument/cs:SASsource"
469        CS_appendMetaData(fileID, preMeta + "/@name",                      preXpath + "/@name", "")
470        CS_appendMetaData(fileID, preMeta + "/radiation",                  preXpath + "/cs:radiation", "")
471        CS_appendMetaData(fileID, preMeta + "/beam/size/@name",            preXpath + "/cs:beam_size/@name", "")
472        CS_appendMetaData(fileID, preMeta + "/beam/size/x",                preXpath + "/cs:beam_size/cs:x", "")
473        CS_appendMetaData(fileID, preMeta + "/beam/size/x@unit",           preXpath + "/cs:beam_size/cs:x/@unit", "")
474        CS_appendMetaData(fileID, preMeta + "/beam/size/y",                preXpath + "/cs:beam_size/cs:y", "")
475        CS_appendMetaData(fileID, preMeta + "/beam/size/y@unit",           preXpath + "/cs:beam_size/cs:y/@unit", "")
476        CS_appendMetaData(fileID, preMeta + "/beam/size/z",                preXpath + "/cs:beam_size/cs:z", "")
477        CS_appendMetaData(fileID, preMeta + "/beam/size/z@unit",           preXpath + "/cs:beam_size/cs:z/@unit", "")
478        CS_appendMetaData(fileID, preMeta + "/beam/shape",                 preXpath + "/cs:beam_shape", "")
479        CS_appendMetaData(fileID, preMeta + "/wavelength",                 preXpath + "/cs:wavelength", "")
480        CS_appendMetaData(fileID, preMeta + "/wavelength/@unit",           preXpath + "/cs:wavelength/@unit", "")
481        CS_appendMetaData(fileID, preMeta + "/wavelength_min",             preXpath + "/cs:wavelength_min", "")
482        CS_appendMetaData(fileID, preMeta + "/wavelength_min/@unit",       preXpath + "/cs:wavelength_min/@unit", "")
483        CS_appendMetaData(fileID, preMeta + "/wavelength_max",             preXpath + "/cs:wavelength_max", "")
484        CS_appendMetaData(fileID, preMeta + "/wavelength_max/@unit",       preXpath + "/cs:wavelength_max/@unit", "")
485        CS_appendMetaData(fileID, preMeta + "/wavelength_spread",          preXpath + "/cs:wavelength_spread", "")
486        CS_appendMetaData(fileID, preMeta + "/wavelength_spread/@unit",    preXpath + "/cs:wavelength_spread/@unit", "")
487
488        // <SASinstrument><SAScollimation> might appear multiple times
489        XmlListXpath(fileID, sasEntryPath+"/cs:SASinstrument//cs:SAScollimation", nsStr)        //output: M_listXPath
490        WAVE/T  M_listXPath
491        DUPLICATE/O/T   M_listXPath, SAScollimationList
492        STRING collimationPath
493        FOR (i = 0; i < DimSize(SAScollimationList, 0); i += 1)
494                preMeta = "SASinstrument/SAScollimation"
495                IF (DimSize(SAScollimationList, 0) > 1)
496                        preMeta += "_" + num2str(i)
497                ENDIF
498                collimationPath = sasEntryPath+"/cs:SASinstrument/cs:SAScollimation["+num2str(i+1)+"]"
499                CS_appendMetaData(fileID, preMeta + "/@name",               collimationPath + "/@name", "")
500                CS_appendMetaData(fileID, preMeta + "/length",              collimationPath + "/cs:length", "")
501                CS_appendMetaData(fileID, preMeta + "/length_unit",         collimationPath + "/cs:length/@unit", "")
502                FOR (j = 0; j < DimSize(M_listXPath, 0); j += 1)        // aperture may be repeated!
503                        IF (DimSize(M_listXPath, 0) == 1)
504                                preMeta = "SASinstrument/SAScollimation/aperture"
505                        ELSE
506                                preMeta = "SASinstrument/SAScollimation/aperture_" + num2str(j)
507                        ENDIF
508                        preXpath = collimationPath + "/cs:aperture["+num2str(j+1)+"]"
509                        CS_appendMetaData(fileID, preMeta + "/@name",         preXpath + "/@name", "")
510                        CS_appendMetaData(fileID, preMeta + "/type",          preXpath + "/cs:type", "")
511                        CS_appendMetaData(fileID, preMeta + "/size/@name",     preXpath + "/cs:size/@name", "")
512                        CS_appendMetaData(fileID, preMeta + "/size/x",        preXpath + "/cs:size/cs:x", "")
513                        CS_appendMetaData(fileID, preMeta + "/size/x/@unit",   preXpath + "/cs:size/cs:x/@unit", "")
514                        CS_appendMetaData(fileID, preMeta + "/size/y",        preXpath + "/cs:size/cs:y", "")
515                        CS_appendMetaData(fileID, preMeta + "/size/y/@unit",   preXpath + "/cs:size/cs:y/@unit", "")
516                        CS_appendMetaData(fileID, preMeta + "/size/z",        preXpath + "/cs:size/cs:z", "")
517                        CS_appendMetaData(fileID, preMeta + "/size/z/@unit",   preXpath + "/cs:size/cs:z/@unit", "")
518                        CS_appendMetaData(fileID, preMeta + "/distance",       preXpath + "/cs:distance", "")
519                        CS_appendMetaData(fileID, preMeta + "/distance/@unit", preXpath + "/cs:distance/@unit", "")
520                ENDFOR
521        ENDFOR
522
523        // <SASinstrument><SASdetector> might appear multiple times
524        XmlListXpath(fileID, sasEntryPath+"/cs:SASinstrument//cs:SASdetector", nsStr)   //output: M_listXPath
525        WAVE/T  M_listXPath
526        DUPLICATE/O/T   M_listXPath, SASdetectorList
527        FOR (i = 0; i < DimSize(SASdetectorList, 0); i += 1)
528                preMeta = "SASinstrument/SASdetector"
529                IF (DimSize(SASdetectorList, 0) > 1)
530                        preMeta += "_" + num2str(i)
531                ENDIF
532                detectorPath = sasEntryPath+"/cs:SASinstrument/cs:SASdetector["+num2str(i+1)+"]"
533                CS_appendMetaData(fileID, preMeta + "/@name",                    detectorPath + "/cs:name", "")
534                CS_appendMetaData(fileID, preMeta + "/SDD",                              detectorPath + "/cs:SDD", "")
535                CS_appendMetaData(fileID, preMeta + "/SDD/@unit",                        detectorPath + "/cs:SDD/@unit", "")
536                CS_appendMetaData(fileID, preMeta + "/offset/@name",             detectorPath + "/cs:offset/@name", "")
537                CS_appendMetaData(fileID, preMeta + "/offset/x",                 detectorPath + "/cs:offset/cs:x", "")
538                CS_appendMetaData(fileID, preMeta + "/offset/x/@unit",           detectorPath + "/cs:offset/cs:x/@unit", "")
539                CS_appendMetaData(fileID, preMeta + "/offset/y",                 detectorPath + "/cs:offset/cs:y", "")
540                CS_appendMetaData(fileID, preMeta + "/offset/y/@unit",           detectorPath + "/cs:offset/cs:y/@unit", "")
541                CS_appendMetaData(fileID, preMeta + "/offset/z",                 detectorPath + "/cs:offset/cs:z", "")
542                CS_appendMetaData(fileID, preMeta + "/offset/z/@unit",           detectorPath + "/cs:offset/cs:z/@unit", "")
543
544                CS_appendMetaData(fileID, preMeta + "/orientation/@name",        detectorPath + "/cs:orientation/@name", "")
545                CS_appendMetaData(fileID, preMeta + "/orientation/roll",         detectorPath + "/cs:orientation/cs:roll", "")
546                CS_appendMetaData(fileID, preMeta + "/orientation/roll/@unit",   detectorPath + "/cs:orientation/cs:roll/@unit", "")
547                CS_appendMetaData(fileID, preMeta + "/orientation/pitch",        detectorPath + "/cs:orientation/cs:pitch", "")
548                CS_appendMetaData(fileID, preMeta + "/orientation/pitch/@unit",   detectorPath + "/cs:orientation/cs:pitch/@unit", "")
549                CS_appendMetaData(fileID, preMeta + "/orientation/yaw",          detectorPath + "/cs:orientation/cs:yaw", "")
550                CS_appendMetaData(fileID, preMeta + "/orientation/yaw/@unit",    detectorPath + "/cs:orientation/cs:yaw/@unit", "")
551
552                CS_appendMetaData(fileID, preMeta + "/beam_center/@name",        detectorPath + "/cs:beam_center/@name", "")
553                CS_appendMetaData(fileID, preMeta + "/beam_center/x",            detectorPath + "/cs:beam_center/cs:x", "")
554                CS_appendMetaData(fileID, preMeta + "/beam_center/x/@unit",      detectorPath + "/cs:beam_center/cs:x/@unit", "")
555                CS_appendMetaData(fileID, preMeta + "/beam_center/y",            detectorPath + "/cs:beam_center/cs:y", "")
556                CS_appendMetaData(fileID, preMeta + "/beam_center/y/@unit",      detectorPath + "/cs:beam_center/cs:y/@unit", "")
557                CS_appendMetaData(fileID, preMeta + "/beam_center/z",            detectorPath + "/cs:beam_center/cs:z", "")
558                CS_appendMetaData(fileID, preMeta + "/beam_center/z/@unit",      detectorPath + "/cs:beam_center/cs:z/@unit", "")
559
560                CS_appendMetaData(fileID, preMeta + "/pixel_size/@name",         detectorPath + "/cs:pixel_size/@name", "")
561                CS_appendMetaData(fileID, preMeta + "/pixel_size/x",             detectorPath + "/cs:pixel_size/cs:x", "")
562                CS_appendMetaData(fileID, preMeta + "/pixel_size/x/@unit",       detectorPath + "/cs:pixel_size/cs:x/@unit", "")
563                CS_appendMetaData(fileID, preMeta + "/pixel_size/y",             detectorPath + "/cs:pixel_size/cs:y", "")
564                CS_appendMetaData(fileID, preMeta + "/pixel_size/y/@unit",       detectorPath + "/cs:pixel_size/cs:y/@unit", "")
565                CS_appendMetaData(fileID, preMeta + "/pixel_size/z",             detectorPath + "/cs:pixel_size/cs:z", "")
566                CS_appendMetaData(fileID, preMeta + "/pixel_size/z/@unit",       detectorPath + "/cs:pixel_size/cs:z/@unit", "")
567
568                CS_appendMetaData(fileID, preMeta + "/slit_length",                    detectorPath + "/cs:slit_length", "")
569                CS_appendMetaData(fileID, preMeta + "/slit_length/@unit",              detectorPath + "/cs:slit_length/@unit", "")
570        ENDFOR
571
572        // <SASprocess> might appear multiple times
573        XmlListXpath(fileID, sasEntryPath+"//cs:SASprocess", nsStr)     //output: M_listXPath
574        WAVE/T  M_listXPath
575        DUPLICATE/O/T   M_listXPath, SASprocessList
576        STRING SASprocessPath, prefix
577        FOR (i = 0; i < DimSize(SASprocessList, 0); i += 1)
578                preMeta = "SASprocess"
579                IF (DimSize(SASprocessList, 0) > 1)
580                        preMeta += "_" + num2str(i)
581                ENDIF
582                SASprocessPath = sasEntryPath+"/cs:SASprocess["+num2str(i+1)+"]"
583                CS_appendMetaData(fileID, preMeta+"/@name",        SASprocessPath + "/@name", "")
584                CS_appendMetaData(fileID, preMeta+"/name",         SASprocessPath + "/cs:name", "")
585                CS_appendMetaData(fileID, preMeta+"/date",                 SASprocessPath + "/cs:date", "")
586                CS_appendMetaData(fileID, preMeta+"/description",   SASprocessPath + "/cs:description", "")
587                XmlListXpath(fileID, SASprocessPath+"//cs:term", nsStr)
588                FOR (j = 0; j < DimSize(M_listXPath, 0); j += 1)
589                        prefix = SASprocessPath + "/cs:term[" + num2str(j+1) + "]"
590                        CS_appendMetaData(fileID, preMeta+"/term_"+num2str(j)+"/@name",     prefix + "/@name", "")
591                        CS_appendMetaData(fileID, preMeta+"/term_"+num2str(j)+"/@unit",           prefix + "/@unit", "")
592                        CS_appendMetaData(fileID, preMeta+"/term_"+num2str(j),                            prefix, "")
593                ENDFOR
594                // ignore <SASprocessnote>
595        ENDFOR
596
597        // <SASnote> might appear multiple times
598        XmlListXpath(fileID, sasEntryPath+"//cs:SASnote", nsStr)        //output: M_listXPath
599        WAVE/T  M_listXPath
600        DUPLICATE/O/T   M_listXPath, SASnoteList
601        FOR (i = 0; i < DimSize(SASnoteList, 0); i += 1)
602                preMeta = "SASnote"
603                IF (DimSize(SASnoteList, 0) > 1)
604                        preMeta += "_" + num2str(i)
605                ENDIF
606                notePath = sasEntryPath+"//cs:SASnote["+num2str(i+1)+"]"
607                CS_appendMetaData(fileID, preMeta+"/@name",     notePath + "/@name", "")
608                CS_appendMetaData(fileID, preMeta,              notePath, "")
609        ENDFOR
610
611        KillWaves/Z M_listXPath, detailsList, SAScollimationList, SASdetectorList, SASprocessList, SASnoteList
612END
613
614// ==================================================================
615
616FUNCTION/S CS_1i_locateTitle(fileID, SASentryPath)
617        VARIABLE fileID
618        STRING SASentryPath
619        STRING TitlePath, Title
620        SVAR nsPre = root:Packages:CS_XMLreader:nsPre
621        SVAR nsStr = root:Packages:CS_XMLreader:nsStr
622
623        // /cs:SASroot/cs:SASentry/cs:Title is the expected location, but it could be empty
624        TitlePath = SASentryPath + "/cs:Title"
625        Title = XMLstrFmXpath(fileID,  TitlePath, nsStr, "")
626        // search harder for a title
627        IF (strlen(Title) == 0)
628                TitlePath = SASentryPath + "/@name"
629                Title = XMLstrFmXpath(fileID,  TitlePath, nsStr, "")
630        ENDIF
631        IF (strlen(Title) == 0)
632                TitlePath = SASentryPath + "/cs:SASsample/cs:ID"
633                Title = XMLstrFmXpath(fileID,  TitlePath, nsStr, "")
634        ENDIF
635        IF (strlen(Title) == 0)
636                TitlePath = SASentryPath + "/cs:SASsample/@name"
637                Title = XMLstrFmXpath(fileID,  TitlePath, nsStr, "")
638        ENDIF
639        IF (strlen(Title) == 0)
640                // last resort: make up a title
641                Title = "SASentry"
642                TitlePath = ""
643        ENDIF
644        PRINT "\t Title:", Title
645        RETURN(Title)
646END
647
648// ==================================================================
649
650FUNCTION CS_appendMetaData(fileID, key, xpath, value)
651        VARIABLE fileID
652        STRING key, xpath, value
653        WAVE/T metadata
654        STRING k, v
655
656        SVAR nsPre = root:Packages:CS_XMLreader:nsPre
657        SVAR nsStr = root:Packages:CS_XMLreader:nsStr
658
659        k = TrimWS(key)
660        IF (  strlen(k) > 0 )
661                IF ( strlen(xpath) > 0 )
662                        value = XMLstrFmXpath(fileID,  xpath, nsStr, "")
663                ENDIF
664                // What if the value string has a ";" embedded?
665                //  This could complicate (?compromise?) the wavenote "key=value;" syntax.
666                //  But let the caller deal with it.
667                v = TrimWS(ReplaceString(";", value, " :semicolon: "))
668                IF ( strlen(v) > 0 )
669                        VARIABLE last
670                        last = DimSize(metadata, 0)
671                        Redimension/N=(last+1, 2) metadata
672                        metadata[last][0] = k
673                        metadata[last][1] = v
674                ENDIF
675        ENDIF
676END
677
678// ==================================================================
679
680Function/T   TrimWS(str)
681    // TrimWhiteSpace (code from Jon Tischler)
682    String str
683    return TrimWSL(TrimWSR(str))
684End
685
686// ==================================================================
687
688Function/T   TrimWSL(str)
689    // TrimWhiteSpaceLeft (code from Jon Tischler)
690    String str
691    Variable i, N=strlen(str)
692    for (i=0;char2num(str[i])<=32 && i<N;i+=1)    // find first non-white space
693    endfor
694    return str[i,Inf]
695End
696
697// ==================================================================
698
699Function/T   TrimWSR(str)
700    // TrimWhiteSpaceRight (code from Jon Tischler)
701    String str
702    Variable i
703    for (i=strlen(str)-1; char2num(str[i])<=32 && i>=0; i-=1)    // find last non-white space
704    endfor
705    return str[0,i]
706End
707
708// ==================================================================
709// ==================================================================
710// ==================================================================
711
712
713FUNCTION prj_grabMyXmlData()
714        STRING srcDir = "root:Packages:CS_XMLreader"
715        STRING destDir = "root:PRJ_canSAS"
716        STRING srcFolder, destFolder, theFolder
717        Variable i
718        NewDataFolder/O  $destDir               // for all my imported data
719        FOR ( i = 0; i < CountObjects(srcDir, 4) ; i += 1 )
720                theFolder = GetIndexedObjName(srcDir, 4, i)
721                srcFolder = srcDir + ":" + theFolder
722                destFolder = destDir + ":" + theFolder
723                // PRINT srcFolder, destFolder
724                IF (DataFolderExists(destFolder))
725                        // !!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
726                        // need to find unique name for destination
727                        // Persons who implement this properly should be more elegant
728                        // For now, I will blast the existing and proceed blindly.
729                        KillDataFolder/Z  $destFolder           // clear out any previous work
730                        DuplicateDataFolder $srcFolder, $destFolder
731                ELSE
732                        DuplicateDataFolder $srcFolder, $destFolder
733                ENDIF
734        ENDFOR
735END
736
737FUNCTION prjTest_cansas1d()
738        // unit tests for the routines under prj-readXML.ipf
739        STRING theFile
740        STRING fList = ""
741        VARIABLE i, result, timerID, seconds
742        // build a table of test data sets
743        fList = AddListItem("elmo.xml",                                 fList, ";", Inf)                // non-existent file
744        fList = AddListItem("cansasXML.ipf",                    fList, ";", Inf)                // this file (should fail on XML parsing)
745        fList = AddListItem("../examples/book.xml",                             fList, ";", Inf)                // good XML example file but not canSAS, not even close
746        fList = AddListItem("../examples/bimodal-test1.xml",            fList, ";", Inf)                // simple dataset
747        fList = AddListItem("../examples/testers/test3.xml",                                    fList, ";", Inf)                // no number provided for wavelength, others, too
748        fList = AddListItem("../examples/ISIS_SANS_Example.xml",        fList, ";", Inf)                // from S. King, 2008-03-17
749        fList = AddListItem("../examples/W1W2.xml",                             fList, ";", Inf)                // from S. King, 2008-03-17
750        fList = AddListItem("../examples/ill_sasxml_example.xml",       fList, ";", Inf)                // from canSAS 2007 meeting, reformatted
751        fList = AddListItem("../examples/isis_sasxml_example.xml",      fList, ";", Inf)                // from canSAS 2007 meeting, reformatted
752        fList = AddListItem("../examples/r586.xml",                                     fList, ";", Inf)                // from canSAS 2007 meeting, reformatted
753        fList = AddListItem("../examples/r597.xml",                                     fList, ";", Inf)                // from canSAS 2007 meeting, reformatted
754        fList = AddListItem("../examples/xg009036_001.xml",             fList, ";", Inf)                // foreign elements with other namespaces
755        fList = AddListItem("../examples/cs_collagen.xml",                      fList, ";", Inf)                // another simple dataset, bare minimum info
756        fList = AddListItem("../examples/cs_collagen_full.xml",                 fList, ";", Inf)                // more Q range than previous
757        fList = AddListItem("../examples/cs_af1410.xml",                        fList, ";", Inf)                // multiple SASentry and SASdata elements
758        fList = AddListItem("../examples/cs_rr_polymers.xml",           fList, ";", Inf)                // Round Robin polymer samples from John Barnes @ NIST
759        fList = AddListItem("../examples/cansas1d-template.xml",        fList, ";", Inf)                // multiple SASentry and SASdata elements
760        fList = AddListItem("../examples/1998spheres.xml",                      fList, ";", Inf)                // 2 SASentry, few thousand data points each
761        fList = AddListItem("../examples/does-not-exist-file.xml",              fList, ";", Inf)                // non-existent file
762        fList = AddListItem("../examples/s81-polyurea.xml",                     fList, ";", Inf)                // polyurea from APS/USAXS/Indra (with extra metadata)
763        fList = AddListItem("../examples/GLASSYC_C4G8G9_w_TL.xml",                      fList, ";", Inf)                // from S. King, with transmission spectra
764       
765        // try to load each data set in the table
766        FOR ( i = 0; i < ItemsInList(fList) ; i += 1 )
767                theFile = StringFromList(i, fList)                                      // walk through all test files
768                // PRINT "file: ", theFile
769                pathInfo home
770                //IF (CS_XmlReader(theFile) == 0)                                       // did the XML reader return without an error code?
771                timerID = StartMStimer
772                result = CS_XmlReader(ParseFilePath(5,S_path,"*",0,0) + theFile)
773                seconds = StopMSTimer(timerID) * 1.0e-6
774                PRINT "\t Completed in ", seconds, " seconds"
775                IF (result == 0)    // did the XML reader return without an error code?
776                        prj_grabMyXmlData()                                             // move the data to my directory
777                ENDIF
778        ENDFOR
779END
780
781
782FUNCTION testCollette()
783                                        // !!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
784                                        //          THIS IS JUST AN EXAMPLE
785
786// suggestions from ISIS users
787        // 3.   Loading actual data from LOQ caused some problems.
788        //      Data created by Colette names files with run number.
789        //      When entering full path to load the data if you use "…\example\31531.X" Igor will read \3 as a character.
790        //      A simple fix which has worked for this is to use / instead of \ e.g. "…\example/31531.X".
791       
792        //4.    Once data is loaded in Igor it is relatively easy to work with but would be nicer if the SASdata
793        //      was loaded into root directory (named using run number rather than generically as it is at the moment) rather than another folder.
794        //This becomes more problematic when two samples are being loaded for comparison.
795        //      Although still relatively easy to work with, changing the folders can lead to mistakes being made.
796
797        //Say, for Run=31531, then Qsas_31531
798
799        CS_XmlReader("../examples/W1W2.XML")
800        STRING srcDir = "root:Packages:CS_XMLreader"
801        STRING destDir = "root", importFolder, target
802        Variable i, j
803        FOR ( i = 0; i < CountObjects(srcDir, 4) ; i += 1 )
804                SetDataFolder $srcDir
805                importFolder = GetIndexedObjName(srcDir, 4, i)
806                SetDataFolder $importFolder
807                IF ( EXISTS( "metadata" ) == 1 )
808                        // looks like a SAS data folder
809                        WAVE/T metadata
810                        STRING Run = ""
811                        FOR (j = 0; j < DimSize(metadata, 0); j += 1)
812                                IF ( CmpStr( "Run", metadata[j][0]) == 0 )
813                                        // get the Run number and "clean" it up a bit
814                                        Run = TrimWS(  ReplaceString("\\", metadata[j][1], "/")  )
815                                        // !!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
816                                        // need to find unique name for destination waves       
817                                        //          THIS IS JUST AN EXAMPLE
818                                        // Persons who implement this properly should be more elegant
819                                        // For now, I will blast any existing and proceed blindly.
820                                        target = "root:Qsas_" + Run
821                                        Duplicate/O Qsas, $target
822                                        target = "root:Isas_" + Run
823                                        Duplicate/O Isas, $target
824                                        IF ( exists( "Idev" ) == 1 )
825                                                target = "root:Idev_" + Run
826                                                Duplicate/O Idev, $target
827                                        ENDIF
828                                        IF ( exists( "Qdev" ) == 1 )
829                                                target = "root:Qdev_" + Run
830                                                Duplicate/O Qdev, $target
831                                        ENDIF
832                                        IF ( exists( "dQw" ) == 1 )
833                                                target = "root:QdQw_" + Run
834                                                Duplicate/O dQw, $target
835                                        ENDIF
836                                        IF ( exists( "dQl" ) == 1 )
837                                                target = "root:dQl_" + Run
838                                                Duplicate/O dQl, $target
839                                        ENDIF
840                                        IF ( exists( "Qmean" ) == 1 )
841                                                target = "root:Qmean_" + Run
842                                                Duplicate/O Qmean, $target
843                                        ENDIF
844                                        IF ( exists( "Shadowfactor" ) == 1 )
845                                                target = "root:Shadowfactor_" + Run
846                                                Duplicate/O Shadowfactor, $target
847                                        ENDIF
848                                        target = "root:metadata_" + Run
849                                        Duplicate/O/T metadata, $target
850                                        BREAK
851                                ENDIF
852                        ENDFOR
853                ENDIF
854        ENDFOR
855
856        SetDataFolder root:
857END
858
859#else   // if( Exists("XmlOpenFile") )
860        // No XMLutils XOP: provide dummy function so that IgorPro can compile dependent support code
861        FUNCTION CS_XmlReader(fileName)
862            String fileName
863            Abort  "XML function provided by XMLutils XOP is not available, get the XOP from : http://www.igorexchange.com/project/XMLutils (see http://www.smallangles.net/wgwiki/index.php/cansas1d_binding_IgorPro for details)"
864            RETURN(-6)
865        END
866#endif  // if( Exists("XmlOpenFile") )
Note: See TracBrowser for help on using the repository browser.