source: sans/Dev/trunk/NCNR_User_Procedures/Common/cansasXML.ipf @ 928

Last change on this file since 928 was 928, checked in by srkline, 9 years ago

adding cansasXML.ipf back in with consistent name

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