source: sans/Dev/trunk/NCNR_User_Procedures/Common/cansasXML_v11.ipf @ 601

Last change on this file since 601 was 570, checked in by srkline, 13 years ago

Change (1):
In preparation for release, updated pragma IgorVersion?=6.1 in all procedures

Change (2):
As a side benefit of requiring 6.1, we can use the MultiThread? keyword to thread any model function we like. The speed benefit is only noticeable on functions that require at least one integration and at least 100 points (resolution smearing is NOT threaded, too many threadSafe issues, too little benefit). I have chosen to use the MultiThread? only on the XOP assignment. In the Igor code there are too many functions that are not explicitly declared threadsafe, making for a mess.

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