Changeset 39


Ignore:
Timestamp:
May 19, 2008 5:43:18 AM (11 years ago)
Author:
prjemian
Message:

fixes #10 (http://svn.smallangles.net/trac/canSAS/ticket/10)
improved efficiency of XMLreader;
now reads entire test suite under 10 seconds;
added cursory ISIS loader example

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 1dwg/trunk/IgorPro/cansasXML.ipf

    r31 r39  
    11#pragma rtGlobals=1             // Use modern global access method. 
    2 #pragma version=1.05 
     2#pragma version=1.06 
    33 
    44// file:        cansasXML.ipf 
    55// author:      Pete R. Jemian <jemian@anl.gov> 
    6 // date:        2008-03-31 
     6// date:        2008-05-18 
    77// purpose:  implement an IgorPro file reader to read the canSAS 1-D reduced SAS data in XML files 
    88//                      adheres to the cansas1d/1.0 standard 
     9// readme:    http://www.smallangles.net/wgwiki/index.php/cansas1d_binding_IgorPro 
    910// URL: http://www.smallangles.net/wgwiki/index.php/cansas1d_documentation 
    1011// 
    1112// requires:    IgorPro (http://www.wavemetrics.com/) 
    1213//                              XMLutils - XOP (http://www.igorexchange.com/project/XMLutils) 
     14 
     15// ================================================================== 
     16// CS_XmlReader("bimodal-test1.xml") 
     17// CS_XmlReader("1998spheres.xml") 
     18// CS_XmlReader("xg009036_001.xml") 
     19// CS_XmlReader("s81-polyurea.xml") 
     20// CS_XmlReader("cs_af1410.xml") 
     21// ================================================================== 
     22 
    1323 
    1424FUNCTION CS_XmlReader(fileName) 
     
    1828        //              0 : successful 
    1929        //              -1: XML file not found 
    20         //              -2: root element is not <SASroot> 
     30        //              -2: root element is not <SASroot> with valid canSAS namespace 
    2131        //              -3: <SASroot> version  is not 1.0 
    2232        //              -4: no <SASentry> elements 
     
    4252        VARIABLE fileID 
    4353        STRING/G errorMsg, xmlFile 
    44         MAKE/T/N=(0,3)/O metadata 
    45         CS_appendMetaData("xmlFile", "", fileName) 
    4654        xmlFile = fileName 
    4755        fileID = XmlOpenFile(fileName)                  // open and parse the XMLfile 
     
    6068        ENDIF 
    6169 
    62         // 
    63         // index the XML element list 
    64         // 
    65         XmlElemList(fileID)                                     // load the elementlist into W_ElementList 
    66         WAVE/T  W_ElementList                           // This declaration comes _after_ XmlElemList() is called 
    67  
    68         // qualify the XML file, don't allow just any ole XML. 
    69         IF ( CmpStr(W_ElementList[0][3], "SASroot") != 0 )              // deftly avoid namespace 
    70                 errorMsg = fileName + ": root element is not <SASroot>" 
     70        // check for canSAS namespace string, returns "" if not valid or not found 
     71        STRING/G ns = CS_getDefaultNamespace(fileID) 
     72        IF (strlen(ns) == 0 ) 
     73                errorMsg = "root element is not <SASroot> with valid canSAS namespace" 
    7174                PRINT errorMsg 
    72                 XmlCloseFile(fileID,0) 
    7375                SetDataFolder $origFolder 
    74                 RETURN(-2)                                              // not a canSAS XML file 
    75         ENDIF 
    76  
    77         // make an index to speed up searching through column 0 
    78         Make/O/T/N=(DimSize(W_ElementList, 0)) W_ElementList_Col0 
    79         W_ElementList_Col0 = W_ElementList[p][0] 
    80         STRING/G nsPre = "", nsStr = "" 
    81         CS_registerNameSpaces(fileID)                           // to assist XPath construction 
    82  
    83         // identify supported versions of canSAS XML standard 
    84         STRING version 
    85         version = StringByKey("version", W_ElementList[0][2]) 
    86         CS_appendMetaData("cansas_version", CS_XPath_NS("/SASroot/@version"), version) 
    87         STRSWITCH(version)       
    88         CASE "1.0":                                                     // version 1.0 of the canSAS 1-D reduced SAS data standard 
     76                RETURN(-2)                                              // root element is not <SASroot> with valid canSAS namespace 
     77        ENDIF 
     78        STRING/G nsPre = "cs" 
     79        STRING/G nsStr = nsPre + "=" + ns 
     80 
     81        SVAR nsPre = root:Packages:CS_XMLreader:nsPre 
     82        SVAR nsStr = root:Packages:CS_XMLreader:nsStr 
     83         
     84        STRSWITCH(ns)    
     85        CASE "cansas1d/1.0":                                                    // version 1.0 of the canSAS 1-D reduced SAS data standard 
    8986                PRINT fileName, "\t\t identified as: cansas1d/1.0 XML file" 
    90                 returnCode = CS_1i_parseXml(fileID) 
     87                returnCode = CS_1i_parseXml(fileID)                     //  This is where the action happens! 
    9188                IF (returnCode != 0) 
    9289                        IF (strlen(errorMsg) == 0) 
     
    9996                ENDIF 
    10097                BREAK 
    101         CASE "2.0a":                                            // unsupported 
     98        CASE "cansas1d/2.0a":                                           // unsupported 
    10299        DEFAULT:                                                        // optional default expression executed 
    103                 errorMsg = fileName + ": <SASroot> version (" + version + ") is not supported" 
     100                errorMsg = fileName + ": <SASroot>, namespace (" + ns + ") is not supported" 
    104101                PRINT errorMsg 
    105102                XmlCloseFile(fileID,0) 
     
    111108        fileID = -1 
    112109 
     110        SetDataFolder root:Packages:CS_XMLreader 
     111        KillWaves/Z M_listXPath, SASentryList 
    113112        SetDataFolder $origFolder 
    114113        RETURN(0)                                                       // execution finished OK 
    115114END 
    116115 
     116FUNCTION/S CS_getDefaultNamespace(fileID) 
     117        // Test here (by guessing) for the various known namespaces. 
     118        // Return the one found in the "schemaLocation" attribute 
     119        // since the XMLutils XOP does not provide any xmlns attributes. 
     120        // It is possible to call XMLelemList and get the namespace directly 
     121        // but that call can be expensive (time) when there are lots of elements. 
     122        VARIABLE fileID 
     123        STRING ns = "", thisNS 
     124        STRING p = "cs" 
     125        VARIABLE i, item 
     126        MAKE/T/N=(1)/O nsList           // list of all possible namespaces 
     127        nsList[0] = "cansas1d/1.0"              // first version of canSAS 1-D reduced SAS 
     128 
     129        FOR (item = 0; item < DimSize(nsList, 0); item += 1)            // loop over all possible namespaces 
     130                XMLlistAttr(fileID, "/cs:SASroot", p+"="+nsList[item]) 
     131                WAVE/T M_listAttr 
     132                FOR (i = 0; i < DimSize(M_listAttr,0); i+=1)                    // loop over all available attributes 
     133                        // Expect the required canSAS XML header (will fail if "schemalocation" is not found) 
     134                        IF ( CmpStr(  LowerStr(M_listAttr[i][1]),  LowerStr("schemaLocation") ) == 0 ) 
     135                                thisNS = StringFromList( 0, M_listAttr[i][2], " " )     // get the first string 
     136                                IF ( strlen(thisNS) == strlen(M_listAttr[i][2]) )               // just in case tab-delimited 
     137                                        thisNS = StringFromList( 0, M_listAttr[i][2], "\t" )    // get the first string 
     138                                ENDIF 
     139                                IF ( CmpStr(  TrimWS(thisNS),  nsList[item] ) == 0 ) 
     140                                        ns = nsList[item] 
     141                                        BREAK           // found it! 
     142                                ENDIF 
     143                        ENDIF 
     144                ENDFOR 
     145                IF (strlen(ns)) 
     146                        BREAK           // found it! 
     147                ENDIF 
     148        ENDFOR 
     149 
     150        KillWaves/Z nsList, M_listAttr 
     151        RETURN ns 
     152END 
     153 
    117154// ================================================================== 
    118155 
    119156FUNCTION CS_1i_parseXml(fileID) 
    120157        VARIABLE fileID 
    121         WAVE/T W_ElementList 
    122158        SVAR errorMsg, xmlFile 
    123         STRING/G Title 
    124         STRING XPathStr, Title_folder, SASdata_folder 
    125         STRING SASentryPath, SASdataPath, RunNum 
     159        STRING/G Title, Title_folder 
    126160        VARIABLE i, j, index, SASdata_index, returnCode = 0 
    127161 
     162        SVAR nsPre = root:Packages:CS_XMLreader:nsPre 
     163        SVAR nsStr = root:Packages:CS_XMLreader:nsStr 
     164 
    128165        // locate all the SASentry elements 
    129         CS_simpleXmlListXpath(fileID, "", "/SASroot//SASentry") 
    130         WAVE/T  W_listXPath 
    131         // (safer to copy W_listxpath to a local variable and allow for other calls to XMLlistXpath) 
    132         DUPLICATE/O/T   W_listXPath, SASentryList 
    133  
    134         IF (numpnts(SASentryList) < 1) 
    135                 errorMsg = "could not find any SASentry elements in XML file" 
    136                 PRINT errorMsg 
    137                 RETURN(-4)                                              // no <SASentry> elements 
    138         ENDIF 
    139  
    140         // Should we test here for all required elements?  That could be tedious.  And possibly unnecessary. 
    141  
    142         // process each SASentry element 
    143         DUPLICATE/O/T metadata, metadata_file 
    144         FOR (i = 0; i < numpnts(SASentryList); i += 1) 
    145                 index = CS_findElementIndex(SASentryList[i]) 
    146                 DUPLICATE/O/T metadata_file, metadata 
    147                 Title = CS_1i_locateTitle(fileID, CS_correctedXpathStr(SASentryList[i]))                // look in several places or use default title 
    148                 Title_folder = CleanupName(Title, 0) 
    149                 IF ( CheckName(Title_folder, 11) != 0 ) 
    150                         Title_folder = UniqueName(Title_folder, 11, 0) 
    151                 ENDIF 
    152                 NewDataFolder/O  $Title_folder 
    153                 STRING/G FolderList = "" 
    154                 FolderList = AddListItem(":"+Title_folder+":", FolderList, ";", Inf) 
    155                 // 
    156                 // CS_correctedXpathStr 
    157                 SASentryPath = CS_correctedXpathStr(SASentryList[i]) 
    158                 CS_1i_collectMetadata(fileID, SASentryPath) 
    159                 // 
    160                 // next, extract each SASdata block into a subfolder 
    161                 CS_simpleXmlListXpath(fileID, SASentryPath, "//SASdata")        //output: W_listXPath 
    162                 DUPLICATE/O/T   W_listXPath, SASdataList 
    163                 IF (numpnts(SASdataList) == 1) 
    164                         // only one SASdata element, place data waves in Title folder 
    165                         SASdataPath = CS_correctedXpathStr(SASdataList[0]) 
    166                         SASdata_folder = ":" + Title_folder + ":" 
    167                         RunNum = "/Run" 
    168                         CS_appendMetaData( "Run",                               SASentryPath+CS_XPath_NS(RunNum),                               "") 
    169                         CS_appendMetaData( "Run_name",                  SASentryPath+CS_XPath_NS(RunNum + "/@name"),    "") 
    170                         CS_appendMetaData( "SASdata_name",      SASdataPath+CS_XPath_NS("/@name"),                              "") 
    171                         PRINT "\t\t dataFolder:", SASdata_folder 
    172                         CS_1i_fillMetadataTable(fileID) 
    173                         IF (CS_1i_extractSasData(fileID, SASdataPath, SASdata_folder)) 
    174                                 // non-zero return code means an error, message is in errorMsg 
    175                                 // What to do now? 
    176                                 //      Proceed with that knowledge or discard the data folder? 
    177                                 //      Go with the discard for now. 
    178                                 returnCode += 1                         // for later 
    179                                 PRINT "\t\t" + errorMsg 
    180                                 KillDataFolder/Z $Title_folder          // only 1 SASdata 
    181                                 // RETURN(1)                            // Can't return now.  What about other SASentry elements? 
    182                                 BREAK 
    183                         ENDIF 
     166        //      assume nsPre = "cs" otherwise 
     167        // "/"+nsPre+":SASroot//"+nsPre+":SASentry" 
     168        XmlListXpath(fileID, "/cs:SASroot//cs:SASentry", nsStr) 
     169        WAVE/T  M_listXPath 
     170        STRING          SASentryPath 
     171        DUPLICATE/O/T   M_listXPath, SASentryList 
     172 
     173        FOR (i=0; i < DimSize(SASentryList, 0); i += 1) 
     174                SASentryPath = SASentryList[i][0] 
     175                SetDataFolder root:Packages:CS_XMLreader 
     176                 
     177                title =  CS_1i_locateTitle(fileID, SASentryPath) 
     178                Title_folder = CS_cleanFolderName(Title) 
     179                NewDataFolder/O/S  $Title_folder 
     180 
     181                XmlListXpath(fileID, SASentryPath + "//cs:SASdata", nsStr) 
     182                WAVE/T  M_listXPath 
     183                IF ( DimSize(M_listXPath, 0) == 1) 
     184                        CS_1i_getOneSASdata(fileID, Title, M_listXPath[0][0]) 
     185                        CS_1i_collectMetadata(fileID, SASentryPath) 
    184186                ELSE 
    185                         // multiple SASdata elements, place data waves in subfolders 
    186                         DUPLICATE/O/T metadata, metadata_entry 
    187                         FOR (j = 0; j < numpnts(SASdataList); j += 1) 
    188                                 DUPLICATE/O/T metadata_entry, metadata 
    189                                 SASdata_index = CS_findElementIndex(SASdataList[j]) 
    190                                 SASdataPath = CS_correctedXpathStr(SASdataList[j]) 
    191                                 SASdata_folder = CleanupName(StringByKey("name", W_ElementList[SASdata_index][2]), 0) 
    192                                 PRINT "\t\t dataFolder:", SASdata_folder 
    193                                 RunNum = "/Run["+num2str(j+1)+"]" 
    194                                 CS_appendMetaData( "Run"+num2str(j),                            SASdataPath+"/.."+CS_XPath_NS(RunNum),                          "") 
    195                                 CS_appendMetaData( "Run"+num2str(j)+"_name",            SASdataPath+"/.."+CS_XPath_NS(RunNum + "/@name"),       "") 
    196                                 CS_appendMetaData( "SASdata"+num2str(j)+"_name",        SASdataPath+CS_XPath_NS("/@name"),                                      "") 
    197                                 SetDataFolder $Title_folder 
    198                                 IF ( CheckName(SASdata_folder, 11) != 0 ) 
    199                                         SASdata_folder = UniqueName(SASdata_folder, 11, 0) 
    200                                 ENDIF 
    201                                 NewDataFolder/O  $SASdata_folder 
    202                                 SetDataFolder :: 
    203                                 SASdata_folder =  ":" + Title_folder + ":" + SASdata_folder + ":" 
    204                                 FolderList = AddListItem(SASdata_folder, FolderList, ";", Inf) 
    205                                 //--- 
    206                                 CS_1i_fillMetadataTable(fileID) 
    207                                 IF (CS_1i_extractSasData(fileID, SASdataPath, SASdata_folder)) 
    208                                         // non-zero return code means an error, message is in errorMsg 
    209                                         // What to do now? 
    210                                         //      Proceed with that knowledge or discard the data folder? 
    211                                         //      Go with the discard for now. 
    212                                         returnCode += 1                                         // for later 
    213                                         PRINT "\t\t" + errorMsg 
    214                                         KillDataFolder/Z $SASdata_folder                // just this SASdata 
    215                                         // RETURN(1)                                            // Can't return now.  What about other SASentry elements? 
     187                        FOR (j = 0; j < DimSize(M_listXPath, 0); j += 1) 
     188                                STRING SASdataFolder = CS_cleanFolderName("SASdata_" + num2str(j)) 
     189                                NewDataFolder/O/S  $SASdataFolder 
     190                                CS_1i_getOneSASdata(fileID, Title, M_listXPath[j][0]) 
     191                                CS_1i_collectMetadata(fileID, SASentryPath) 
     192                                SetDataFolder ::                        // back up to parent directory 
     193                        ENDFOR 
     194                ENDIF 
     195                KillWaves/Z M_listXPath 
     196        ENDFOR 
     197 
     198        SetDataFolder root:Packages:CS_XMLreader 
     199        KillWaves/Z M_listXPath, SASentryList 
     200        RETURN(returnCode) 
     201END 
     202 
     203// ================================================================== 
     204 
     205FUNCTION/S CS_cleanFolderName(proposal) 
     206        STRING proposal 
     207        STRING result 
     208        result = CleanupName(proposal, 0) 
     209        IF ( CheckName(result, 11) != 0 ) 
     210                result = UniqueName(result, 11, 0) 
     211        ENDIF 
     212        RETURN result 
     213END 
     214 
     215// ================================================================== 
     216 
     217FUNCTION CS_1i_getOneSASdata(fileID, Title, SASdataPath) 
     218        VARIABLE fileID 
     219        STRING Title, SASdataPath 
     220        SVAR nsPre = root:Packages:CS_XMLreader:nsPre 
     221        SVAR nsStr = root:Packages:CS_XMLreader:nsStr 
     222        VARIABLE i 
     223        STRING SASdata_name, suffix = "" 
     224 
     225        //grab the data and put it in the working data folder 
     226        CS_1i_GetReducedSASdata(fileID, SASdataPath) 
     227 
     228        //start the metadata 
     229        MAKE/O/T/N=(0,2) metadata 
     230 
     231        SVAR xmlFile = root:Packages:CS_XMLreader:xmlFile 
     232        CS_appendMetaData(fileID, "xmlFile", "", xmlFile) 
     233 
     234        SVAR ns = root:Packages:CS_XMLreader:ns 
     235        CS_appendMetaData(fileID, "namespace", "", ns) 
     236        CS_appendMetaData(fileID, "title", "", Title) 
     237         
     238        XmlListXpath(fileID, SASdataPath + "/..//cs:Run", nsStr) 
     239        WAVE/T  M_listXPath 
     240        FOR (i=0; i < DimSize(M_listXPath, 0); i += 1) 
     241                IF ( DimSize(M_listXPath, 0) > 1 ) 
     242                        suffix = "_" + num2str(i) 
     243                ENDIF 
     244                CS_appendMetaData(fileID, "Run" + suffix,  M_listXPath[i][0], "") 
     245                CS_appendMetaData(fileID, "Run/@name" + suffix,  M_listXPath[i][0] + "/@name", "") 
     246        ENDFOR 
     247 
     248        SASdata_name = TrimWS(XMLstrFmXpath(fileID,  SASdataPath + "/@name", nsStr, "")) 
     249        CS_appendMetaData(fileID, "SASdata/@name", "", SASdata_name) 
     250 
     251        KillWaves/Z M_listXPath 
     252END 
     253 
     254// ================================================================== 
     255 
     256FUNCTION CS_1i_getOneVector(file,prefix,XML_name,Igor_name) 
     257        VARIABLE file 
     258        STRING prefix,XML_name,Igor_name 
     259        SVAR nsPre = root:Packages:CS_XMLreader:nsPre 
     260        SVAR nsStr = root:Packages:CS_XMLreader:nsStr 
     261 
     262        XmlWaveFmXpath(file,prefix+XML_name,nsStr,"")   //this loads ALL the vector's nodes at the same time 
     263        WAVE/T M_xmlcontent 
     264        WAVE/T W_xmlContentNodes 
     265        IF (DimSize(M_xmlcontent, 0))   //this is a test to see if the nodes exist.  this isn't strictly necessary if you know they're there 
     266                IF (DimSize(M_xmlcontent,1)>DimSize(M_xmlcontent,0))    //if you're not in vector mode 
     267                        MatrixTranspose M_xmlcontent 
     268                ENDIF 
     269                MAKE/O/D/N=(DimSize(M_xmlcontent, 0)) $Igor_name 
     270                WAVE vect = $Igor_name 
     271                vect=str2num(M_xmlcontent) 
     272        ENDIF 
     273        KILLWAVES/Z M_xmlcontent, W_xmlContentNodes 
     274END 
     275 
     276// ================================================================== 
     277 
     278FUNCTION CS_1i_GetReducedSASdata(fileID, SASdataPath) 
     279        VARIABLE fileID 
     280        STRING SASdataPath 
     281        SVAR nsPre = root:Packages:CS_XMLreader:nsPre 
     282        SVAR nsStr = root:Packages:CS_XMLreader:nsStr 
     283        STRING prefix = "" 
     284        VARIABLE pos 
     285 
     286        VARIABLE cansasStrict = 1               // !!!software developer's choice!!! 
     287        IF (cansasStrict)               // only get known canSAS data vectors 
     288                prefix = SASdataPath + "//cs:" 
     289                // load ALL nodes of each vector (if exists) at tthe same time 
     290                CS_1i_getOneVector(fileID, prefix, "Q",                 "Qsas") 
     291                CS_1i_getOneVector(fileID, prefix, "I",                 "Isas") 
     292                CS_1i_getOneVector(fileID, prefix, "Idev",              "Idev") 
     293                CS_1i_getOneVector(fileID, prefix, "Qdev",              "Qdev") 
     294                CS_1i_getOneVector(fileID, prefix, "dQw",       "dQw") 
     295                CS_1i_getOneVector(fileID, prefix, "dQl",               "Qsas") 
     296                CS_1i_getOneVector(fileID, prefix, "Qmean",     "Qmean") 
     297                CS_1i_getOneVector(fileID, prefix, "Shadowfactor",      "Shadowfactor") 
     298                // check them for common length 
     299        ELSE                            // search for _ANY_ data vectors 
     300                // find the names of all the data columns and load them as vectors 
     301                // this gets tricky if we want to avoid namespace references 
     302//              XmlListXpath(fileID, "//"+nsPre+":SASentry["+num2istr(i)+"]//"+nsPre+":Idata[1]/*", nsStr) 
     303                XmlListXpath(fileID, SASdataPath+"//cs:Idata[1]/*", nsStr) 
     304                WAVE/T M_listXPath 
     305                STRING xmlElement, xPathStr 
     306                STRING igorWave 
     307                VARIABLE j 
     308                FOR (j = 0; j < DimSize(M_listXPath, 0); j += 1) 
     309                        xmlElement = M_listXPath[j][1] 
     310                        STRSWITCH(xmlElement) 
     311                                CASE "Q":               // IgorPro does not allow a variable named Q 
     312                                CASE "I":                       // or I 
     313                                        igorWave = xmlElement + "sas" 
    216314                                        BREAK 
    217                                 ENDIF 
    218                         ENDFOR  // many SASdata 
    219                 ENDIF                   // 1 or many SASdata 
    220                 MAKE/O/T/N=(3,2) admin 
    221                 admin[0][0] = "xmlFile" 
    222                 admin[0][1] = xmlFile 
    223                 admin[1][0] = "FolderList" 
    224                 admin[1][1] = FolderList 
    225                 admin[2][0] = "numSASdata" 
    226                 admin[2][1] = num2str(numpnts(SASdataList)) 
    227                 Title_folder = ":" + Title_folder + ":" 
    228                 MoveWave admin, $Title_folder 
    229                 MoveString FolderList, $Title_folder 
    230         ENDFOR          // each SASentry 
    231  
    232         RETURN(returnCode) 
     315                                DEFAULT: 
     316                                        igorWave = xmlElement           // can we trust this one? 
     317                        ENDSWITCH 
     318                        xPathStr = M_listXPath[j][0]                                                    // clear name reference 
     319                        pos = strsearch(xPathStr, "/", Inf, 3)                                  // peel off the tail of the string and reform 
     320                        xmlElement = xPathStr[pos,Inf]                                          // find last element on the path 
     321                        prefix = xPathStr[0, pos-1-4]+"/*"                                              // ALL Idata elements 
     322                        CS_1i_getOneVector(fileID,prefix, xmlElement, igorWave)         // loads ALL rows (Idata) of the column at the same time 
     323                ENDFOR 
     324                // check them for common length 
     325        ENDIF 
     326  
     327        //get rid of any mess 
     328        KILLWAVES/z M_listXPath 
    233329END 
    234330 
     
    238334        VARIABLE fileID 
    239335        STRING sasEntryPath 
    240         VARIABLE i 
     336        VARIABLE i, j 
    241337        WAVE/T metadata 
    242338        STRING suffix = "" 
    243339        STRING value, detailsPath, detectorPath, notePath 
     340 
     341        SVAR nsPre = root:Packages:CS_XMLreader:nsPre 
     342        SVAR nsStr = root:Packages:CS_XMLreader:nsStr 
     343 
    244344        // collect some metadata 
    245345        // first, fill a table with keywords, and XPath locations, 3rd column will be values 
    246346 
    247347        // handle most <SASsample> fields 
    248         CS_appendMetaData("sample_ID",                                          sasEntryPath+CS_XPath_NS("/SASsample/ID"), "") 
    249         CS_appendMetaData("sample_thickness",                           sasEntryPath+CS_XPath_NS("/SASsample/thickness"), "") 
    250         CS_appendMetaData("sample_thickness_unit",                      sasEntryPath+CS_XPath_NS("/SASsample/thickness/@unit"), "") 
    251         CS_appendMetaData("sample_transmission",                        sasEntryPath+CS_XPath_NS("/SASsample/transmission"), "") 
    252         CS_appendMetaData("sample_temperature",                         sasEntryPath+CS_XPath_NS("/SASsample/temperature"), "") 
    253         CS_appendMetaData("sample_temperature_unit",            sasEntryPath+CS_XPath_NS("/SASsample/temperature/@unit"), "") 
    254         CS_appendMetaData("sample_position_x",                          sasEntryPath+CS_XPath_NS("/SASsample/position/x"), "") 
    255         CS_appendMetaData("sample_position_x_unit",                     sasEntryPath+CS_XPath_NS("/SASsample/position/x/@unit"), "") 
    256         CS_appendMetaData("sample_position_y",                          sasEntryPath+CS_XPath_NS("/SASsample/position/y"), "") 
    257         CS_appendMetaData("sample_position_y_unit",                     sasEntryPath+CS_XPath_NS("/SASsample/position/y/@unit"), "") 
    258         CS_appendMetaData("sample_position_z",                          sasEntryPath+CS_XPath_NS("/SASsample/position/z"), "") 
    259         CS_appendMetaData("sample_position_z_unit",                     sasEntryPath+CS_XPath_NS("/SASsample/position/z/@unit"), "") 
    260         CS_appendMetaData("sample_orientation_roll",                    sasEntryPath+CS_XPath_NS("/SASsample/orientation/roll"), "") 
    261         CS_appendMetaData("sample_orientation_roll_unit",               sasEntryPath+CS_XPath_NS("/SASsample/orientation/roll/@unit"), "") 
    262         CS_appendMetaData("sample_orientation_pitch",           sasEntryPath+CS_XPath_NS("/SASsample/orientation/pitch"), "") 
    263         CS_appendMetaData("sample_orientation_pitch_unit",      sasEntryPath+CS_XPath_NS("/SASsample/orientation/pitch/@unit"), "") 
    264         CS_appendMetaData("sample_orientation_yaw",                     sasEntryPath+CS_XPath_NS("/SASsample/orientation/yaw"), "") 
    265         CS_appendMetaData("sample_orientation_yaw_unit",        sasEntryPath+CS_XPath_NS("/SASsample/orientation/yaw/@unit"), "") 
     348        CS_appendMetaData(fileID, "sample/ID",                                          sasEntryPath + "/cs:SASsample/cs:ID", "") 
     349        CS_appendMetaData(fileID, "sample/thickness",                           sasEntryPath + "/cs:SASsample/cs:thickness", "") 
     350        CS_appendMetaData(fileID, "sample/thickness/@unit",             sasEntryPath + "/cs:SASsample/cs:thickness/@unit", "") 
     351        CS_appendMetaData(fileID, "sample/transmission",                        sasEntryPath + "/cs:SASsample/cs:transmission", "") 
     352        CS_appendMetaData(fileID, "sample/temperature",                         sasEntryPath + "/cs:SASsample/cs:temperature", "") 
     353        CS_appendMetaData(fileID, "sample/temperature/@unit",           sasEntryPath + "/cs:SASsample/cs:temperature/@unit", "") 
     354        CS_appendMetaData(fileID, "sample/position/x",                          sasEntryPath + "/cs:SASsample/cs:position/cs:x", "") 
     355        CS_appendMetaData(fileID, "sample/position/x/@unit",            sasEntryPath + "/cs:SASsample/cs:position/cs:x/@unit", "") 
     356        CS_appendMetaData(fileID, "sample/position/y",                          sasEntryPath + "/cs:SASsample/cs:position/cs:y", "") 
     357        CS_appendMetaData(fileID, "sample/position/y/@unit",            sasEntryPath + "/cs:SASsample/cs:position/cs:y/@unit", "") 
     358        CS_appendMetaData(fileID, "sample/position/z",                          sasEntryPath + "/cs:SASsample/cs:position/cs:z", "") 
     359        CS_appendMetaData(fileID, "sample/position/z/@unit",            sasEntryPath + "/cs:SASsample/cs:position/cs:z/@unit", "") 
     360        CS_appendMetaData(fileID, "sample/orientation/roll",                    sasEntryPath + "/cs:SASsample/cs:orientation/cs:roll", "") 
     361        CS_appendMetaData(fileID, "sample/orientation/roll/@unit",      sasEntryPath + "/cs:SASsample/cs:orientation/cs:roll/@unit", "") 
     362        CS_appendMetaData(fileID, "sample/orientation/pitch",           sasEntryPath + "/cs:SASsample/cs:orientation/cs:pitch", "") 
     363        CS_appendMetaData(fileID, "sample/orientation/pitch/@unit",     sasEntryPath + "/cs:SASsample/cs:orientation/cs:pitch/@unit", "") 
     364        CS_appendMetaData(fileID, "sample/orientation/yaw",                     sasEntryPath + "/cs:SASsample/cs:orientation/cs:yaw", "") 
     365        CS_appendMetaData(fileID, "sample/orientation/yaw/@unit",       sasEntryPath + "/cs:SASsample/cs:orientation/cs:yaw/@unit", "") 
    266366        // <SASsample><details> might appear multiple times, too! 
    267         CS_simpleXmlListXpath(fileID, sasEntryPath, "/SASsample//details")      //output: W_listXPath 
    268         DUPLICATE/O/T   W_listXPath, detailsList 
     367        XmlListXpath(fileID, sasEntryPath+"/cs:SASsample//cs:details", nsStr)   //output: M_listXPath 
     368        WAVE/T  M_listXPath 
     369        DUPLICATE/O/T   M_listXPath, detailsList 
    269370        suffix = "" 
    270         FOR (i = 0; i < numpnts(detailsList); i += 1) 
    271                 IF (numpnts(detailsList) > 1) 
    272                         suffix = num2str(i) 
    273                 ENDIF 
    274                 detailsPath = CS_correctedXpathStr(detailsList[i]) 
    275                 CS_appendMetaData("sample_details"+suffix+"_name",      detailsPath+CS_XPath_NS("/@name"), "") 
    276                 CS_appendMetaData("sample_details"+suffix,                      detailsPath, "") 
     371        FOR (i = 0; i < DimSize(detailsList, 0); i += 1) 
     372                IF (DimSize(detailsList, 0) > 1) 
     373                        suffix = "_" + num2str(i) 
     374                ENDIF 
     375                detailsPath = detailsList[i][0] 
     376                CS_appendMetaData(fileID, "sample/details"+suffix+"/@name",     detailsPath + "/@name", "") 
     377                CS_appendMetaData(fileID, "sample/details"+suffix,              detailsPath, "") 
    277378        ENDFOR 
    278379 
    279380 
    280381        // <SASinstrument> 
    281         CS_appendMetaData("Instrument_name", sasEntryPath+CS_XPath_NS("/SASinstrument/name"), "") 
    282         CS_appendMetaData("Instrument_attr_name", sasEntryPath+CS_XPath_NS("/SASinstrument/@name"), "") 
     382        CS_appendMetaData(fileID, "Instrument/name",            sasEntryPath + "/cs:SASinstrument/cs:name", "") 
     383        CS_appendMetaData(fileID, "Instrument/@name",   sasEntryPath + "/cs:SASinstrument/@name", "") 
    283384 
    284385        // <SASinstrument><SASsource> 
    285         CS_appendMetaData("source_name", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/@name"), "") 
    286         CS_appendMetaData("radiation", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/radiation"), "") 
    287         CS_appendMetaData("beam_size_name", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/beam_size/@name"), "") 
    288         CS_appendMetaData("beam_size_x", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/beam_size/x"), "") 
    289         CS_appendMetaData("beam_size_x_unit", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/beam_size/x/@unit"), "") 
    290         CS_appendMetaData("beam_size_y", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/beam_size/y"), "") 
    291         CS_appendMetaData("beam_size_y_unit", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/beam_size/y/@unit"), "") 
    292         CS_appendMetaData("beam_size_z", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/beam_size/z"), "") 
    293         CS_appendMetaData("beam_size_z_unit", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/beam_size/z/@unit"), "") 
    294         CS_appendMetaData("beam_shape", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/beam_shape"), "") 
    295         CS_appendMetaData("wavelength", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength"), "") 
    296         CS_appendMetaData("wavelength_unit", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength/@unit"), "") 
    297         CS_appendMetaData("wavelength_min", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength_min"), "") 
    298         CS_appendMetaData("wavelength_min_unit", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength_min/@unit"), "") 
    299         CS_appendMetaData("wavelength_max", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength_max"), "") 
    300         CS_appendMetaData("wavelength_max_unit", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength_max/@unit"), "") 
    301         CS_appendMetaData("wavelength_spread", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength_spread"), "") 
    302         CS_appendMetaData("wavelength_spread_unit", sasEntryPath+CS_XPath_NS("/SASinstrument/SASsource/wavelength_spread/@unit"), "") 
    303  
    304         // ignore <SASinstrument><SAScollimation> for now 
    305         CS_simpleXmlListXpath(fileID, sasEntryPath, "/SASinstrument//SAScollimation")           //output: W_listXPath 
    306         DUPLICATE/O/T   W_listXPath, SAScollimationList 
     386        CS_appendMetaData(fileID, "source/@name",               sasEntryPath + "/cs:SASinstrument/cs:SASsource/@name", "") 
     387        CS_appendMetaData(fileID, "radiation",                  sasEntryPath + "/cs:SASinstrument/cs:SASsource/cs:radiation", "") 
     388        CS_appendMetaData(fileID, "beam/size/@name",            sasEntryPath + "/cs:SASinstrument/cs:SASsource/cs:beam_size/@name", "") 
     389        CS_appendMetaData(fileID, "beam/size/x",                sasEntryPath + "/cs:SASinstrument/cs:SASsource/cs:beam_size/cs:x", "") 
     390        CS_appendMetaData(fileID, "beam/size/x@unit",           sasEntryPath + "/cs:SASinstrument/cs:SASsource/cs:beam_size/cs:x/@unit", "") 
     391        CS_appendMetaData(fileID, "beam/size/y",                sasEntryPath + "/cs:SASinstrument/cs:SASsource/cs:beam_size/cs:y", "") 
     392        CS_appendMetaData(fileID, "beam/size/y@unit",           sasEntryPath + "/cs:SASinstrument/cs:SASsource/cs:beam_size/cs:y/@unit", "") 
     393        CS_appendMetaData(fileID, "beam/size/z",                sasEntryPath + "/cs:SASinstrument/cs:SASsource/cs:beam_size/cs:z", "") 
     394        CS_appendMetaData(fileID, "beam/size/z@unit",           sasEntryPath + "/cs:SASinstrument/cs:SASsource/cs:beam_size/cs:z/@unit", "") 
     395        CS_appendMetaData(fileID, "beam/shape",                 sasEntryPath + "/cs:SASinstrument/cs:SASsource/cs:beam_shape", "") 
     396        CS_appendMetaData(fileID, "wavelength",                 sasEntryPath + "/cs:SASinstrument/cs:SASsource/cs:wavelength", "") 
     397        CS_appendMetaData(fileID, "wavelength/@unit",           sasEntryPath + "/cs:SASinstrument/cs:SASsource/cs:wavelength/@unit", "") 
     398        CS_appendMetaData(fileID, "wavelength_min",             sasEntryPath + "/cs:SASinstrument/cs:SASsource/cs:wavelength_min", "") 
     399        CS_appendMetaData(fileID, "wavelength_min/@unit",       sasEntryPath + "/cs:SASinstrument/cs:SASsource/cs:wavelength_min/@unit", "") 
     400        CS_appendMetaData(fileID, "wavelength_max",             sasEntryPath + "/cs:SASinstrument/cs:SASsource/cs:wavelength_max", "") 
     401        CS_appendMetaData(fileID, "wavelength_max/@unit",       sasEntryPath + "/cs:SASinstrument/cs:SASsource/cs:wavelength_max/@unit", "") 
     402        CS_appendMetaData(fileID, "wavelength_spread",          sasEntryPath + "/cs:SASinstrument/cs:SASsource/cs:wavelength_spread", "") 
     403        CS_appendMetaData(fileID, "wavelength_spread/@unit",    sasEntryPath + "/cs:SASinstrument/cs:SASsource/cs:wavelength_spread/@unit", "") 
     404 
     405        // <SASinstrument><SAScollimation> might appear multiple times 
     406        XmlListXpath(fileID, sasEntryPath+"/cs:SASinstrument//cs:SAScollimation", nsStr)        //output: M_listXPath 
     407        WAVE/T  M_listXPath 
     408        DUPLICATE/O/T   M_listXPath, SAScollimationList 
    307409        STRING collimationPath 
    308410        suffix = "" 
    309         FOR (i = 0; i < numpnts(SAScollimationList); i += 1) 
    310                 IF (numpnts(SAScollimationList) > 1) 
    311                         suffix = num2str(i) 
    312                 ENDIF 
    313                 collimationPath = CS_correctedXpathStr(SAScollimationList[i]) 
    314                 CS_appendMetaData("collimation_name"+suffix,    collimationPath+CS_XPath_NS("/@name"), "") 
    315                 CS_appendMetaData("collimation_length"+suffix,  collimationPath+CS_XPath_NS("/length"), "") 
    316                 CS_appendMetaData("collimation_length_unit"+suffix,     collimationPath+CS_XPath_NS("/length/@unit"), "") 
    317                 CS_appendMetaData("collimation_aperture_name"+suffix,   collimationPath+CS_XPath_NS("/aperture/@name"), "") 
    318                 CS_appendMetaData("collimation_aperture_type"+suffix,   collimationPath+CS_XPath_NS("/aperture/type"), "") 
    319                 CS_appendMetaData("collimation_aperture_size_name"+suffix,      collimationPath+CS_XPath_NS("/aperture/size/@name"), "") 
    320                 CS_appendMetaData("collimation_aperture_size_x"+suffix,         collimationPath+CS_XPath_NS("/aperture/size/x"), "") 
    321                 CS_appendMetaData("collimation_aperture_size_x_unit"+suffix,    collimationPath+CS_XPath_NS("/aperture/size/x/@unit"), "") 
    322                 CS_appendMetaData("collimation_aperture_size_y"+suffix,         collimationPath+CS_XPath_NS("/aperture/size/y"), "") 
    323                 CS_appendMetaData("collimation_aperture_size_y_unit"+suffix,    collimationPath+CS_XPath_NS("/aperture/size/y/@unit"), "") 
    324                 CS_appendMetaData("collimation_aperture_size_z"+suffix,         collimationPath+CS_XPath_NS("/aperture/size/z"), "") 
    325                 CS_appendMetaData("collimation_aperture_size_z_unit"+suffix,    collimationPath+CS_XPath_NS("/aperture/size/z/@unit"), "") 
    326                 CS_appendMetaData("collimation_aperture_distance"+suffix,       collimationPath+CS_XPath_NS("/aperture/distance"), "") 
    327                 CS_appendMetaData("collimation_aperture_distance_unit"+suffix,  collimationPath+CS_XPath_NS("/aperture/distance/@unit"), "") 
     411        FOR (i = 0; i < DimSize(SAScollimationList, 0); i += 1) 
     412                IF (DimSize(SAScollimationList, 0) > 1) 
     413                        suffix = "_" + num2str(i) 
     414                ENDIF 
     415                collimationPath = SAScollimationList[i][0] 
     416                CS_appendMetaData(fileID, "collimation/@name"+suffix,                   collimationPath + "/@name", "") 
     417                CS_appendMetaData(fileID, "collimation/length"+suffix,                  collimationPath + "/cs:length", "") 
     418                CS_appendMetaData(fileID, "collimation/length_unit"+suffix,             collimationPath + "/cs:length/@unit", "") 
     419                CS_appendMetaData(fileID, "collimation/aperture/@name"+suffix,          collimationPath + "/cs:aperture/@name", "") 
     420                CS_appendMetaData(fileID, "collimation/aperture/type"+suffix,           collimationPath + "/cs:aperture/cs:type", "") 
     421                CS_appendMetaData(fileID, "collimation/aperture/size/@name"+suffix,     collimationPath + "/cs:aperture/cs:size/@name", "") 
     422                CS_appendMetaData(fileID, "collimation/aperture/size/x"+suffix,         collimationPath + "/cs:aperture/cs:size/cs:x", "") 
     423                CS_appendMetaData(fileID, "collimation/aperture/size/x/@unit"+suffix,   collimationPath + "/cs:aperture/cs:size/cs:x/@unit", "") 
     424                CS_appendMetaData(fileID, "collimation/aperture/size/y"+suffix,         collimationPath + "/cs:aperture/cs:size/cs:y", "") 
     425                CS_appendMetaData(fileID, "collimation/aperture/size/y/@unit"+suffix,   collimationPath + "/cs:aperture/cs:size/cs:y/@unit", "") 
     426                CS_appendMetaData(fileID, "collimation/aperture/size/z"+suffix,         collimationPath + "/cs:aperture/cs:size/cs:z", "") 
     427                CS_appendMetaData(fileID, "collimation/aperture/size/z/@unit"+suffix,   collimationPath + "/cs:aperture/cs:size/cs:z/@unit", "") 
     428                CS_appendMetaData(fileID, "collimation/aperture/distance"+suffix,       collimationPath + "/cs:aperture/cs:distance", "") 
     429                CS_appendMetaData(fileID, "collimation/aperture/distance/@unit"+suffix, collimationPath + "/cs:aperture/cs:distance/@unit", "") 
    328430        ENDFOR 
    329431 
    330432        // <SASinstrument><SASdetector> might appear multiple times 
    331         CS_simpleXmlListXpath(fileID, sasEntryPath, "/SASinstrument//SASdetector")      //output: W_listXPath 
    332         DUPLICATE/O/T   W_listXPath, SASdetectorList 
     433        XmlListXpath(fileID, sasEntryPath+"/cs:SASinstrument//cs:SASdetector", nsStr)   //output: M_listXPath 
     434        WAVE/T  M_listXPath 
     435        DUPLICATE/O/T   M_listXPath, SASdetectorList 
    333436        suffix = "" 
    334         FOR (i = 0; i < numpnts(SASdetectorList); i += 1) 
    335                 IF (numpnts(SASdetectorList) > 1) 
    336                         suffix = num2str(i) 
    337                 ENDIF 
    338                 detectorPath = CS_correctedXpathStr(SASdetectorList[i]) 
    339                 CS_appendMetaData("detector_name"+suffix,       detectorPath+CS_XPath_NS("/name"), "") 
    340                 CS_appendMetaData("SDD"+suffix,                         detectorPath+CS_XPath_NS("/SDD"), "") 
    341                 CS_appendMetaData("SDD"+suffix+"_unit",                 detectorPath+CS_XPath_NS("/SDD/@unit"), "") 
    342                 CS_appendMetaData("detector_offset_name"+suffix,        detectorPath+CS_XPath_NS("/offset/@name"), "") 
    343                 CS_appendMetaData("detector_offset_x"+suffix,           detectorPath+CS_XPath_NS("/offset/x"), "") 
    344                 CS_appendMetaData("detector_offset_x_unit"+suffix,      detectorPath+CS_XPath_NS("/offset/x/@unit"), "") 
    345                 CS_appendMetaData("detector_offset_y"+suffix,           detectorPath+CS_XPath_NS("/offset/y"), "") 
    346                 CS_appendMetaData("detector_offset_y_unit"+suffix,      detectorPath+CS_XPath_NS("/offset/y/@unit"), "") 
    347                 CS_appendMetaData("detector_offset_z"+suffix,           detectorPath+CS_XPath_NS("/offset/z"), "") 
    348                 CS_appendMetaData("detector_offset_z_unit"+suffix,      detectorPath+CS_XPath_NS("/offset/z/@unit"), "") 
    349  
    350                 CS_appendMetaData("detector_orientation_name"+suffix,           detectorPath+CS_XPath_NS("/orientation/@name"), "") 
    351                 CS_appendMetaData("detector_orientation_roll"+suffix,           detectorPath+CS_XPath_NS("/orientation/roll"), "") 
    352                 CS_appendMetaData("detector_orientation_roll_unit"+suffix,      detectorPath+CS_XPath_NS("/orientation/roll/@unit"), "") 
    353                 CS_appendMetaData("detector_orientation_pitch"+suffix,          detectorPath+CS_XPath_NS("/orientation/pitch"), "") 
    354                 CS_appendMetaData("detector_orientation_pitch_unit"+suffix,     detectorPath+CS_XPath_NS("/orientation/pitch/@unit"), "") 
    355                 CS_appendMetaData("detector_orientation_yaw"+suffix,            detectorPath+CS_XPath_NS("/orientation/yaw"), "") 
    356                 CS_appendMetaData("detector_orientation_yaw_unit"+suffix,       detectorPath+CS_XPath_NS("/orientation/yaw/@unit"), "") 
    357  
    358                 CS_appendMetaData("detector_beam_center_name"+suffix,   detectorPath+CS_XPath_NS("/beam_center/@name"), "") 
    359                 CS_appendMetaData("detector_beam_center_x"+suffix,              detectorPath+CS_XPath_NS("/beam_center/x"), "") 
    360                 CS_appendMetaData("detector_beam_center_x_unit"+suffix,         detectorPath+CS_XPath_NS("/beam_center/x/@unit"), "") 
    361                 CS_appendMetaData("detector_beam_center_y"+suffix,              detectorPath+CS_XPath_NS("/beam_center/y"), "") 
    362                 CS_appendMetaData("detector_beam_center_y_unit"+suffix,         detectorPath+CS_XPath_NS("/beam_center/y/@unit"), "") 
    363                 CS_appendMetaData("detector_beam_center_z"+suffix,              detectorPath+CS_XPath_NS("/beam_center/z"), "") 
    364                 CS_appendMetaData("detector_beam_center_z_unit"+suffix,         detectorPath+CS_XPath_NS("/beam_center/z/@unit"), "") 
    365  
    366                 CS_appendMetaData("detector_pixel_size_name"+suffix,    detectorPath+CS_XPath_NS("/pixel_size/@name"), "") 
    367                 CS_appendMetaData("detector_pixel_size_x"+suffix,               detectorPath+CS_XPath_NS("/pixel_size/x"), "") 
    368                 CS_appendMetaData("detector_pixel_size_x_unit"+suffix,  detectorPath+CS_XPath_NS("/pixel_size/x/@unit"), "") 
    369                 CS_appendMetaData("detector_pixel_size_y"+suffix,               detectorPath+CS_XPath_NS("/pixel_size/y"), "") 
    370                 CS_appendMetaData("detector_pixel_size_y_unit"+suffix,  detectorPath+CS_XPath_NS("/pixel_size/y/@unit"), "") 
    371                 CS_appendMetaData("detector_pixel_size_z"+suffix,               detectorPath+CS_XPath_NS("/pixel_size/z"), "") 
    372                 CS_appendMetaData("detector_pixel_size_z_unit"+suffix,  detectorPath+CS_XPath_NS("/pixel_size/z/@unit"), "") 
    373  
    374                 CS_appendMetaData("slit_length"+suffix,                 detectorPath+CS_XPath_NS("/slit_length"), "") 
    375                 CS_appendMetaData("slitLength"+suffix+"_unit",  detectorPath+CS_XPath_NS("/slit_length/@unit"), "") 
    376         ENDFOR 
    377  
    378         // ignore <SASprocess> for now 
     437        FOR (i = 0; i < DimSize(SASdetectorList, 0); i += 1) 
     438                IF (DimSize(SASdetectorList, 0) > 1) 
     439                        suffix = "_" + num2str(i) 
     440                ENDIF 
     441                detectorPath = SASdetectorList[i][0] 
     442                CS_appendMetaData(fileID, "detector/@name"+suffix,                      detectorPath + "/cs:name", "") 
     443                CS_appendMetaData(fileID, "SDD"+suffix,                                 detectorPath + "/cs:SDD", "") 
     444                CS_appendMetaData(fileID, "SDD"+suffix+"/@unit",                        detectorPath + "/cs:SDD/@unit", "") 
     445                CS_appendMetaData(fileID, "detector/offset/@name"+suffix,               detectorPath + "/cs:offset/@name", "") 
     446                CS_appendMetaData(fileID, "detector/offset/x"+suffix,                   detectorPath + "/cs:offset/cs:x", "") 
     447                CS_appendMetaData(fileID, "detector/offset/x/@unit"+suffix,             detectorPath + "/cs:offset/cs:x/@unit", "") 
     448                CS_appendMetaData(fileID, "detector/offset/y"+suffix,                   detectorPath + "/cs:offset/cs:y", "") 
     449                CS_appendMetaData(fileID, "detector/offset/y/@unit"+suffix,             detectorPath + "/cs:offset/cs:y/@unit", "") 
     450                CS_appendMetaData(fileID, "detector/offset/z"+suffix,                   detectorPath + "/cs:offset/cs:z", "") 
     451                CS_appendMetaData(fileID, "detector/offset/z/@unit"+suffix,             detectorPath + "/cs:offset/cs:z/@unit", "") 
     452 
     453                CS_appendMetaData(fileID, "detector/orientation/@name"+suffix,          detectorPath + "/cs:orientation/@name", "") 
     454                CS_appendMetaData(fileID, "detector/orientation/roll"+suffix,           detectorPath + "/cs:orientation/cs:roll", "") 
     455                CS_appendMetaData(fileID, "detector/orientation/roll/@unit"+suffix,     detectorPath + "/cs:orientation/cs:roll/@unit", "") 
     456                CS_appendMetaData(fileID, "detector/orientation/pitch"+suffix,          detectorPath + "/cs:orientation/cs:pitch", "") 
     457                CS_appendMetaData(fileID, "detector/orientation/pitch/@unit"+suffix,    detectorPath + "/cs:orientation/cs:pitch/@unit", "") 
     458                CS_appendMetaData(fileID, "detector/orientation/yaw"+suffix,            detectorPath + "/cs:orientation/cs:yaw", "") 
     459                CS_appendMetaData(fileID, "detector/orientation/yaw/@unit"+suffix,      detectorPath + "/cs:orientation/cs:yaw/@unit", "") 
     460 
     461                CS_appendMetaData(fileID, "detector/beam_center/@name"+suffix,          detectorPath + "/cs:beam_center/@name", "") 
     462                CS_appendMetaData(fileID, "detector/beam_center/x"+suffix,              detectorPath + "/cs:beam_center/cs:x", "") 
     463                CS_appendMetaData(fileID, "detector/beam_center/x/@unit"+suffix,        detectorPath + "/cs:beam_center/cs:x/@unit", "") 
     464                CS_appendMetaData(fileID, "detector/beam_center/y"+suffix,              detectorPath + "/cs:beam_center/cs:y", "") 
     465                CS_appendMetaData(fileID, "detector/beam_center/y/@unit"+suffix,        detectorPath + "/cs:beam_center/cs:y/@unit", "") 
     466                CS_appendMetaData(fileID, "detector/beam_center/z"+suffix,              detectorPath + "/cs:beam_center/cs:z", "") 
     467                CS_appendMetaData(fileID, "detector/beam_center/z/@unit"+suffix,        detectorPath + "/cs:beam_center/cs:z/@unit", "") 
     468 
     469                CS_appendMetaData(fileID, "detector/pixel_size/@name"+suffix,           detectorPath + "/cs:pixel_size/@name", "") 
     470                CS_appendMetaData(fileID, "detector/pixel_size/x"+suffix,               detectorPath + "/cs:pixel_size/cs:x", "") 
     471                CS_appendMetaData(fileID, "detector/pixel_size/x/@unit"+suffix,         detectorPath + "/cs:pixel_size/cs:x/@unit", "") 
     472                CS_appendMetaData(fileID, "detector/pixel_size/y"+suffix,               detectorPath + "/cs:pixel_size/cs:y", "") 
     473                CS_appendMetaData(fileID, "detector/pixel_size/y/@unit"+suffix,         detectorPath + "/cs:pixel_size/cs:y/@unit", "") 
     474                CS_appendMetaData(fileID, "detector/pixel_size/z"+suffix,               detectorPath + "/cs:pixel_size/cs:z", "") 
     475                CS_appendMetaData(fileID, "detector/pixel_size/z/@unit"+suffix,         detectorPath + "/cs:pixel_size/cs:z/@unit", "") 
     476 
     477                CS_appendMetaData(fileID, "slit_length"+suffix,                         detectorPath + "/cs:slit_length", "") 
     478                CS_appendMetaData(fileID, "slit_length"+suffix+"/@unit",                detectorPath + "/cs:slit_length/@unit", "") 
     479        ENDFOR 
     480 
     481        // <SASprocess> might appear multiple times 
     482        XmlListXpath(fileID, sasEntryPath+"//cs:SASprocess", nsStr)     //output: M_listXPath 
     483        WAVE/T  M_listXPath 
     484        DUPLICATE/O/T   M_listXPath, SASprocessList 
     485        STRING SASprocessPath 
     486        suffix = "" 
     487        FOR (i = 0; i < DimSize(SASprocessList, 0); i += 1) 
     488                IF (DimSize(SASprocessList, 0) > 1) 
     489                        suffix = "_" + num2str(i) 
     490                ENDIF 
     491                SASprocessPath = SASprocessList[i][0] 
     492                CS_appendMetaData(fileID, "process"+suffix+"/@name",            SASprocessPath + "/@name", "") 
     493                CS_appendMetaData(fileID, "process"+suffix+"/name",             SASprocessPath + "/cs:name", "") 
     494                CS_appendMetaData(fileID, "process"+suffix+"/date",                     SASprocessPath + "/cs:date", "") 
     495                CS_appendMetaData(fileID, "process"+suffix+"/description",      SASprocessPath + "/cs:description", "") 
     496                XmlListXpath(fileID, SASprocessList[i][0]+"//cs:term", nsStr) 
     497                FOR (j = 0; j < DimSize(M_listXPath, 0); j += 1) 
     498                        CS_appendMetaData(fileID, "process"+suffix+"/term_"+num2str(j)+"/@name",        M_listXPath[j][0] + "/@name", "") 
     499                        CS_appendMetaData(fileID, "process"+suffix+"/term_"+num2str(j)+"/@unit",                M_listXPath[j][0] + "/@unit", "") 
     500                        CS_appendMetaData(fileID, "process"+suffix+"/term_"+num2str(j),                         M_listXPath[j][0], "") 
     501                ENDFOR 
     502        ENDFOR 
    379503 
    380504        // <SASnote> might appear multiple times 
    381         CS_simpleXmlListXpath(fileID, sasEntryPath, "//SASnote")        //output: W_listXPath 
    382         DUPLICATE/O/T   W_listXPath, SASnoteList 
     505        XmlListXpath(fileID, sasEntryPath+"//cs:SASnote", nsStr)        //output: M_listXPath 
     506        WAVE/T  M_listXPath 
     507        DUPLICATE/O/T   M_listXPath, SASnoteList 
    383508        suffix = "" 
    384         FOR (i = 0; i < numpnts(SASnoteList); i += 1) 
    385                 IF (numpnts(SASnoteList) > 1) 
    386                         suffix = num2str(i) 
    387                 ENDIF 
    388                 notePath = CS_correctedXpathStr(SASnoteList[i]) 
    389                 CS_appendMetaData("SASnote"+suffix+"_name",     notePath+CS_XPath_NS("/@name"), "") 
    390                 CS_appendMetaData("SASnote"+suffix,                             notePath, "") 
    391         ENDFOR 
    392         //CS_1i_fillMetadataTable(fileID) 
    393 END 
    394  
    395 // ================================================================== 
    396  
    397 FUNCTION/S CS_1i_fillMetadataTable(fileID) 
    398         VARIABLE fileID 
    399         WAVE/T metadata 
    400         VARIABLE i 
    401         STRING value 
    402         // +++++++++++++++++++++++++                    // try to fill the value column from the XML data 
    403         FOR (i = 0; i < DimSize(metadata, 0); i += 1) 
    404                 IF (strlen(metadata[i][1]) > 0)                         // XPathStr for this entry? 
    405                         IF (strlen(metadata[i][2])  == 0)                       // not defined yet? 
    406                                 value = CS_XmlStrFmXpath(fileID, metadata[i][1], "")            // get it 
    407                                 // What if the value string has a ";" embedded? 
    408                                 //  This will complicate (?compromise?) the wavenote "key=value;" syntax. 
    409                                 metadata[i][2] = ReplaceString(";", value, " :semicolon: ") 
    410                         ENDIF 
    411                 ENDIF 
    412         ENDFOR 
     509        FOR (i = 0; i < DimSize(SASnoteList, 0); i += 1) 
     510                IF (DimSize(SASnoteList, 0) > 1) 
     511                        suffix = "_" + num2str(i) 
     512                ENDIF 
     513                notePath = SASnoteList[i][0] 
     514                CS_appendMetaData(fileID, "SASnote"+suffix+"/@name",    notePath + "/@name", "") 
     515                CS_appendMetaData(fileID, "SASnote"+suffix,             notePath, "") 
     516        ENDFOR 
     517 
     518        KillWaves/Z M_listXPath, detailsList, SAScollimationList, SASdetectorList, SASprocessList, SASnoteList 
    413519END 
    414520 
     
    418524        VARIABLE fileID 
    419525        STRING SASentryPath 
    420         WAVE/T metadata 
    421526        STRING TitlePath, Title 
    422         // /SASroot/SASentry/Title is the expected location, but it could be empty 
    423         TitlePath = SASentryPath+CS_XPath_NS("/Title") 
    424         Title = CS_XmlStrFmXpath(fileID,  TitlePath, "") 
     527        SVAR nsPre = root:Packages:CS_XMLreader:nsPre 
     528        SVAR nsStr = root:Packages:CS_XMLreader:nsStr 
     529 
     530        // /cs:SASroot/cs:SASentry/cs:Title is the expected location, but it could be empty 
     531        TitlePath = SASentryPath + "/cs:Title" 
     532        Title = XMLstrFmXpath(fileID,  TitlePath, nsStr, "") 
    425533        // search harder for a title 
    426534        IF (strlen(Title) == 0) 
    427                 TitlePath = SASentryPath+CS_XPath_NS("/@name") 
    428                 Title = CS_XmlStrFmXpath(fileID,  TitlePath, "") 
     535                TitlePath = SASentryPath + "/@name" 
     536                Title = XMLstrFmXpath(fileID,  TitlePath, nsStr, "") 
    429537        ENDIF 
    430538        IF (strlen(Title) == 0) 
    431                 TitlePath = SASentryPath+CS_XPath_NS("/SASsample/ID") 
    432                 Title = CS_XmlStrFmXpath(fileID,  TitlePath, "") 
     539                TitlePath = SASentryPath + "/cs:SASsample/cs:ID" 
     540                Title = XMLstrFmXpath(fileID,  TitlePath, nsStr, "") 
    433541        ENDIF 
    434542        IF (strlen(Title) == 0) 
    435                 TitlePath = SASentryPath+CS_XPath_NS("/SASsample/@name") 
    436                 Title = CS_XmlStrFmXpath(fileID,  TitlePath, "") 
     543                TitlePath = SASentryPath + "/cs:SASsample/@name" 
     544                Title = XMLstrFmXpath(fileID,  TitlePath, nsStr, "") 
    437545        ENDIF 
    438546        IF (strlen(Title) == 0) 
     
    442550        ENDIF 
    443551        PRINT "\t Title:", Title 
    444         CS_appendMetaData("title", TitlePath, Title) 
    445552        RETURN(Title) 
    446553END 
     
    448555// ================================================================== 
    449556 
    450 FUNCTION CS_appendMetaData(key, xpath, value) 
     557FUNCTION CS_appendMetaData(fileID, key, xpath, value) 
     558        VARIABLE fileID 
    451559        STRING key, xpath, value 
    452560        WAVE/T metadata 
    453         VARIABLE last 
    454         last = DimSize(metadata, 0) 
    455         Redimension/N=(last+1, 3) metadata 
    456         metadata[last][0] = key 
    457         metadata[last][1] = xpath 
    458         metadata[last][2] = value 
    459 END 
    460  
    461 // ================================================================== 
    462  
    463 FUNCTION CS_findElementIndex(matchStr) 
    464         STRING matchStr 
    465         // 
    466         // support the canSAS XML file reader 
    467         // return index where   g[index][0] == matchStr 
    468         // return -1 if not found 
    469         // 
    470         WAVE/T W_ElementList_Col0 
    471  
    472         FindValue/TEXT=matchStr    W_ElementList_Col0 
    473         RETURN(V_value) 
    474 END 
    475  
    476 // ================================================================== 
    477  
    478 FUNCTION CS_registerNameSpaces(fileID) 
    479         VARIABLE fileID 
    480         // 
    481         // The canSAS 1-D namespace is defined in the <SASroot> element. 
    482         // We can use our own namespace prefix without further concern. 
    483         // Other namespaces may be used in the file but this does not  
    484         // look for foreign (non-canSAS) elements. 
    485         // 
    486         WAVE/T W_ElementList 
    487         SVAR nsPre 
    488         SVAR nsStr 
    489         VARIABLE i, j, index, row 
    490         STRING testStr 
    491         MAKE/T/N=(1,2)/O nsRegistry 
    492         // 
    493         nsStr = W_ElementList[0][1]             // this is the one to use 
    494         nsPre = "" 
    495         IF (strlen(nsStr)) 
    496                 nsPre = "cs:" 
    497                 nsStr = "cs=" + nsStr 
    498         ENDIF 
    499         // 2008-03-14,PRJ: Now, add a workaround for the libxml2 support that affects MacOS. 
    500         //   When using namespaces  
    501         //              W_ElementList[][1] != "" (it shows a namespace for this node) 
    502         //   and with default libxml2 (v2.2) on MacOS, 
    503         //              W_ElementList[][0] != /SASroot/SASentry ... 
    504         //  BUT, on PCs and on MacOS with user-proveded libxml2 (?version?) 
    505         //              W_ElementList[][0] != /*/*[1]   or /*/* ... 
    506         // 
    507         // Need to handle either situation. 
    508         //  Add another column to W_ElementList that shows the corrected absolute  
    509         //      XPath query,  complete with namespace prefix as needed. 
    510         Redimension/N=(DimSize(W_ElementList,0),5) W_ElementList 
    511         W_ElementList[0,Inf][4] = ""                            // clear out the last column (useful only to developer) 
    512         W_ElementList[0][4] = CS_XPath_NS("/"+W_ElementList[0][3]) 
    513         FOR (i = 1; i < DimSize(W_ElementList,0); i += 1) 
    514                 IF (strlen(W_ElementList[i][4]) == 0)           // if not already set, then find absolute XPath string 
    515                         // For now, only handle items in the default namespace. 
    516                         // Takes more work to build in the capability to handle more namespaces 
    517                         // 
    518                         index = CS_findElementIndex(  CS_findLast(W_ElementList[i][0], "/", 1  )  ) 
    519                         testStr = W_ElementList[index][4] + CS_XPath_NS("/"+W_ElementList[i][3]) 
    520                         XMLlistXpath(fileID,testStr,nsStr) 
    521                         IF ( !EXISTS("W_listXPath") ) 
    522                                 PRINT i, testStr, " empty result from XmlListXpath()" 
    523                                 BREAK 
    524                         ENDIF 
    525                         WAVE/T W_listXPath 
    526                         SWITCH(numpnts(W_listXPath)) 
    527                                 CASE 0:                 // What?  Can't find the node we just found? 
    528                                         //PRINT numpnts(W_listXPath), testStr, " !!! WARNING:  <Can't find the node we just found> in CS_registerNameSpaces()" 
    529                                         PRINT i, testStr, " Foreign element namespace detected and ignored" 
    530                                         BREAK 
    531                                 CASE 1:                 // Only one node with this element 
    532                                         W_ElementList[i][4] = testStr 
    533                                         BREAK 
    534                                 DEFAULT:                        // Multiple elements match this node; need to use indices 
    535                                         // PRINT numpnts(W_listXPath), testStr 
    536                                         FOR (j = 0; j < numpnts(W_listXPath); j += 1) 
    537                                                 index = CS_findElementIndex(  W_listXPath[j]  ) 
    538                                                 W_ElementList[index][4] = testStr + "[" + num2str(j+1) + "]" 
    539                                         ENDFOR 
    540                                         BREAK 
    541                         ENDSWITCH 
    542                 ENDIF 
    543         ENDFOR 
    544         // PRINT StringByKey("schemaLocation", W_ElementList[0][2]) 
    545         // 
    546         // <code comes here> 
    547         RETURN(0) 
    548 END 
    549  
    550 // ================================================================== 
    551  
    552 FUNCTION/S CS_findLast(src, matchStr, leftSide) 
    553         STRING src 
    554         STRING matchStr 
    555         VARIABLE leftSide 
    556         // given a source string such as:   /*/*/*[7]/*/*[39]/*[2] 
    557         // return the part on the $leftSide if the $matchStr 
    558         // Examples: 
    559         //       CS_findLast( "/*/*/*[7]/*/*[39]/*[2]"  , "/", 1)                 /*/*/*[7]/*/*[39] 
    560         //       CS_findLast( "/*/*/*[7]/*/*[39]/*[2]"  , "/", 0)                 /*[2] 
    561         //       CS_findLast( "/*/*/*[7]/*/*[39]/*[2]"  , "[", 1)                 /*/*/*[7]/*/*[39]/* 
    562         //       CS_findLast( "/*/*/*[7]/*/*[39]/*[2]"  , "[", 0)                 [2] 
    563         VARIABLE i 
    564         STRING result="", test 
    565         FOR (i=strlen(src)-1; i >= 0; i -= 1) 
    566                 IF (stringmatch(src[i], matchStr )) 
    567                         IF (leftSide) 
    568                                 result = src[0,i-1] 
    569                         ELSE 
    570                                 result = src[i,Inf] 
    571                         ENDIF 
    572                         RETURN(result) 
    573                 ENDIF 
    574         ENDFOR 
    575         RETURN(result) 
    576 END 
    577  
    578 // ================================================================== 
    579  
    580 FUNCTION/S CS_XPath_NS(simpleStr) 
    581         // namespaces complicate the XPath description 
    582         // this function adds namespace info as necessary to simpleStr (an XPath) 
    583         STRING simpleStr 
    584         SVAR nsPre 
    585         STRING result = "", thisChar, lastChar = "" 
    586         VARIABLE i 
    587         FOR (i = 0; i < strlen(simpleStr); i += 1) 
    588                 //PRINT simpleStr[i] 
    589                 thisChar = simpleStr[i] 
    590                 IF ( CmpStr(lastChar, "/") == 0 ) 
    591                         STRSWITCH (thisChar) 
    592                                 CASE "/": 
    593                                 CASE ".": 
    594                                 CASE "@": 
    595                                         BREAK 
    596                                 DEFAULT: 
    597                                         result += nsPre 
    598                         ENDSWITCH 
    599                 ENDIF 
    600                 result += thisChar 
    601                 lastChar = thisChar 
    602         ENDFOR 
    603         RETURN(result) 
    604 END 
    605  
    606 // ================================================================== 
    607  
    608 FUNCTION/S CS_XmlStrFmXpath(fileID, prefix, value) 
    609         VARIABLE fileID 
    610         STRING prefix, value 
    611         SVAR nsStr 
    612         STRING result 
    613         result = TrimWS(XmlStrFmXpath(fileID, prefix + CS_XPath_NS(value), nsStr, "")) 
    614         RETURN( result ) 
    615 END 
    616  
    617 // ================================================================== 
    618  
    619 FUNCTION CS_simpleXmlWaveFmXpath(fileID, prefix, value) 
    620         VARIABLE fileID 
    621         STRING prefix, value 
    622         SVAR nsStr 
    623         XMLwaveFmXpath(fileID, prefix + CS_XPath_NS(value), nsStr, " ")  
    624         // output: M_xmlContent  W_xmlContentNodes 
    625 END 
    626  
    627 // ================================================================== 
    628  
    629 FUNCTION/S CS_correctedXpathStr(indexPath) 
    630         STRING indexPath 
    631         VARIABLE index 
    632         STRING absolutePath 
    633         WAVE/T          W_ElementList 
    634         index  =  CS_findElementIndex(indexPath) 
    635         absolutePath = W_ElementList[index][4]  // use corrected XPath string 
    636         RETURN(absolutePath) 
    637 END 
    638  
    639 // ================================================================== 
    640  
    641 FUNCTION CS_simpleXmlListXpath(fileID, prefix, value) 
    642         VARIABLE fileID 
    643         STRING prefix, value 
    644         SVAR nsStr 
    645         XMLlistXpath(fileID, prefix + CS_XPath_NS(value), nsStr)                // output: W_listXPath 
     561        STRING k, v 
     562 
     563        SVAR nsPre = root:Packages:CS_XMLreader:nsPre 
     564        SVAR nsStr = root:Packages:CS_XMLreader:nsStr 
     565 
     566        k = TrimWS(key) 
     567        IF (  strlen(k) > 0 ) 
     568                IF ( strlen(xpath) > 0 ) 
     569                        value = XMLstrFmXpath(fileID,  xpath, nsStr, "") 
     570                ENDIF 
     571                // What if the value string has a ";" embedded? 
     572                //  This could complicate (?compromise?) the wavenote "key=value;" syntax. 
     573                //  But let the caller deal with it. 
     574                v = TrimWS(ReplaceString(";", value, " :semicolon: ")) 
     575                IF ( strlen(v) > 0 ) 
     576                        VARIABLE last 
     577                        last = DimSize(metadata, 0) 
     578                        Redimension/N=(last+1, 2) metadata 
     579                        metadata[last][0] = k 
     580                        metadata[last][1] = v 
     581                ENDIF 
     582        ENDIF 
    646583END 
    647584 
     
    675612    return str[0,i] 
    676613End 
    677  
    678 // ================================================================== 
    679  
    680 FUNCTION CS_updateWaveNote(wavName, key, value) 
    681         STRING wavName, key, value 
    682         STRING wavenote 
    683         wavenote = ReplaceStringByKey(key, note($wavName), value) 
    684         Note /K $wavName, wavenote 
    685 END 
    686  
    687 // ================================================================== 
    688  
    689 FUNCTION CS_1i_extractIdataColumn2Wave(fileID, basePath, colName, wavName) 
    690         // 
    691         // this function pulls one column of data from each <Idata> element 
    692         // easier to write this as a function than debug it all the times it is needed 
    693         // 
    694         VARIABLE fileID 
    695         STRING basePath, colName, wavName 
    696         STRING unit 
    697         WAVE/T metadata 
    698         VARIABLE i, numPts 
    699  
    700         //      Q values come out in multiple columns. Different nodes means different columns in M_xmlcontent 
    701         //      Multiple values in the SAME node (i.e. a vector) get put in different rows. 
    702         //      We are therefore going to transpose the wave 
    703         //      (Based on example from Andrew R.J. Nelson.) 
    704         CS_simpleXmlWaveFmXpath(fileID, basePath, "//Idata/" + colName) 
    705         WAVE/T  M_xmlcontent, W_xmlcontentnodes 
    706         numPts = numpnts(M_XMLcontent) 
    707         IF (numPts > 0) 
    708                 MatrixTranspose M_XMLcontent 
    709                 MAKE/O/D/N=(numpnts(M_XMLcontent)) $wavName = str2num(M_xmlcontent[p][0]) 
    710                 // don't forget the units!  Assume that all rows have the same "unit" as in the first row. 
    711                 unit = CS_XmlStrFmXpath(fileID, basePath, "/Idata[1]/"+colName+"/@unit") 
    712                 SetScale d 0, 1, unit, $wavName                         // update the wave's "UNITS" string 
    713                 SetScale x 0, 1, unit, $wavName                         // put it here, too, for the Data Browser 
    714                 // put unit directly into wavenote of _this_ wave 
    715                 CS_updateWaveNote(wavName, "unit", unit)                // put UNIT in wavenote 
    716                 // store all the metadata in the wavenote (for now, at least) 
    717                 FOR (i = 0; i < DimSize(metadata, 0); i += 1) 
    718                         IF (strlen(metadata[i][2]) > 0) 
    719                                 // only add defined metadata to the wavenote 
    720                                 CS_updateWaveNote(wavName, metadata[i][0], metadata[i][2]) 
    721                         ENDIF 
    722                 ENDFOR 
    723         ELSE 
    724                 // did not find any data 
    725                 // no need to apply special handling here; do that in the caller 
    726         ENDIF 
    727         //IF (numPts) 
    728         //      PRINT "\t\t\t\t" + wavName + ": found " + num2str(numPts) + " points" 
    729         //ENDIF 
    730         RETURN(numPts) 
    731 END 
    732  
    733 // ================================================================== 
    734  
    735 FUNCTION CS_1i_extractSasData(fileID, SASdataPath, SASdata_folder) 
    736         // 
    737         // extract data from the SASdata/Idata block in a canSAS1d/v1.0 XML file 
    738         //  (1i in the function name signifies this is a function that supports INPUT from version 1.0 XML files) 
    739         // 
    740         //      returns: 
    741         //              0       no error 
    742         //              1       number of points in waves is not the same as Qsas wave 
    743         // 
    744         VARIABLE fileID 
    745         STRING SASdataPath, SASdata_folder 
    746         WAVE/T metadata 
    747         VARIABLE numPts, numQ 
    748         SVAR errorMsg 
    749  
    750         // extract each Idata column into waves 
    751         // ignore the return codes here, check below 
    752         numQ    = CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "Q",                       "Qsas") 
    753         IF (numQ != CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "I",                     "Isas")) 
    754                 errorMsg = "number of points in Qsas and Isas waves are not identical" 
    755                 RETURN(1) 
    756         ENDIF 
    757         numPts = CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "Idev",             "Idev") 
    758         IF (numPts && (numQ != numPts) ) 
    759                 errorMsg = "number of points in Qsas and Idev waves are not identical" 
    760                 RETURN(1) 
    761         ENDIF 
    762         numPts = CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "Qdev",             "Qdev") 
    763         IF (numPts && (numQ != numPts) ) 
    764                 errorMsg = "number of points in Qsas and Qdev waves are not identical" 
    765                 RETURN(1) 
    766         ENDIF 
    767         numPts = CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "dQw",              "dQw") 
    768         IF (numPts && (numQ != numPts) ) 
    769                 errorMsg = "number of points in Qsas and dQw waves are not identical" 
    770                 RETURN(1) 
    771         ENDIF 
    772         numPts = CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "dQl",                      "dQl") 
    773         IF (numPts && (numQ != numPts) ) 
    774                 errorMsg = "number of points in Qsas and dQl waves are not identical" 
    775                 RETURN(1) 
    776         ENDIF 
    777         numPts = CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "Qmean",            "Qmean") 
    778         IF (numPts && (numQ != numPts) ) 
    779                 errorMsg = "number of points in Qsas and Qmean waves are not identical" 
    780                 RETURN(1) 
    781         ENDIF 
    782         numPts = CS_1i_extractIdataColumn2Wave(fileID, SASdataPath, "Shadowfactor",     "Shadowfactor") 
    783         IF (numPts && (numQ != numPts) ) 
    784                 errorMsg = "number of points in Qsas and Shadowfactor waves are not identical" 
    785                 RETURN(1) 
    786         ENDIF 
    787  
    788         PRINT "\t\t\t\t found " + num2str(numpnts(Qsas)) + " points" 
    789  
    790         // move the waves to the sample folder 
    791         // !!!!! Missing Qsas, Isas, Qdev, and/or Idev are a broken data set 
    792         //              This should produce an exception.  Should have been trapped by numPts tests. 
    793         //              Best to return an error code but the caller chain is not ready to pass that to the top level, yet. 
    794         MoveWave Qsas, $SASdata_folder                          // required wave 
    795         MoveWave Isas, $SASdata_folder                          // required wave 
    796         IF (exists("Idev") == 1) 
    797                 MoveWave Idev, $SASdata_folder                  // optional wave 
    798         ENDIF 
    799         IF (exists("Qdev") == 1) 
    800                 MoveWave Qdev, $SASdata_folder                  // optional wave 
    801         ENDIF 
    802         IF (exists("dQw") == 1) 
    803                 MoveWave dQw, $SASdata_folder                   // optional wave 
    804         ENDIF 
    805         IF (exists("dQl") == 1) 
    806                 MoveWave dQl, $SASdata_folder                   // optional wave 
    807         ENDIF 
    808         IF (exists("Qmean") == 1) 
    809                 MoveWave Qmean, $SASdata_folder         // optional wave 
    810         ENDIF 
    811         IF (exists("ShadowFactor") == 1) 
    812                 MoveWave ShadowFactor, $SASdata_folder  // optional wave 
    813         ENDIF 
    814         IF (exists("metadata") == 1) 
    815                 Duplicate/O metadata, $SASdata_folder + "metadata" 
    816         ENDIF 
    817         RETURN(0)                       // no error 
    818 END 
    819  
    820614 
    821615// ================================================================== 
     
    872666        fList = AddListItem("cs_af1410.xml",                    fList, ";", Inf)                // multiple SASentry and SASdata elements 
    873667        fList = AddListItem("cansas1d-template.xml",    fList, ";", Inf)                // multiple SASentry and SASdata elements 
    874         //fList = AddListItem("1998spheres.xml",                        fList, ";", Inf)                // 2 SASentry, few thousand data points each 
     668        fList = AddListItem("1998spheres.xml",                  fList, ";", Inf)                // 2 SASentry, few thousand data points each 
    875669        fList = AddListItem("does-not-exist-file.xml",          fList, ";", Inf)                // non-existent file 
    876670        fList = AddListItem("cs_rr_polymers.xml",               fList, ";", Inf)                // Round Robin polymer samples from John Barnes @ NIST 
     671        fList = AddListItem("s81-polyurea.xml",                         fList, ";", Inf)                // Round Robin polymer samples from John Barnes @ NIST 
     672         
    877673        // try to load each data set in the table 
    878674        FOR ( i = 0; i < ItemsInList(fList) ; i += 1 ) 
     
    908704        XMLcloseFile(fileID,0) 
    909705END 
     706 
     707 
     708FUNCTION testCollette() 
     709 
     710// suggestions from ISIS users 
     711        // 3.   Loading actual data from LOQ caused some problems. Data created by Colette names files with run number. When entering full path to load the data if you use " 
     712\example\31531.X" Igor will read \3 as a character. A simple fix which has worked for this is to use / instead of \ e.g. " 
     713\example/31531.X". 
     714        // I assume this will not be an issue once a proper pull down menu has been created. 
     715         
     716        //4.    Once data is loaded in Igor it is relatively easy to work with but would be nicer if the SASdata was loaded into root directory (named using run number rather than generically as it is at the moment) rather than another folder. 
     717        //This becomes more problematic when two samples are being loaded for comparison. Although still relatively easy to work with, changing the folders can lead to mistakes being made. 
     718 
     719        //Say, for Run=31531, then Qsas_31531 
     720 
     721        CS_XmlReader("W1W2.XML") 
     722        STRING srcDir = "root:Packages:CS_XMLreader" 
     723        STRING destDir = "root", importFolder, target 
     724        Variable i, j 
     725        FOR ( i = 0; i < CountObjects(srcDir, 4) ; i += 1 ) 
     726                SetDataFolder $srcDir 
     727                importFolder = GetIndexedObjName(srcDir, 4, i) 
     728                SetDataFolder $importFolder 
     729                IF ( exists( "metadata" ) == 1 ) 
     730                        // looks like a SAS data folder 
     731                        WAVE/T metadata 
     732                        STRING Run = "" 
     733                        FOR (j = 0; j < DimSize(metadata, 0); j += 1) 
     734                                IF ( CmpStr( "Run", metadata[j][0]) == 0 ) 
     735                                        // get the Run number and "clean" it up a bit 
     736                                        Run = TrimWS(  ReplaceString("\\", metadata[j][1], "/")  ) 
     737                                        // !!!!!!!!!!!!!!!!! NOTE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
     738                                        // need to find unique name for destination waves         
     739                                        //          THIS IS JUST AN EXAMPLE 
     740                                        // Persons who implement this properly should be more elegant 
     741                                        // For now, I will blast any existing and proceed blindly. 
     742                                        target = "root:Qsas_" + Run 
     743                                        Duplicate/O Qsas, $target 
     744                                        target = "root:Isas_" + Run 
     745                                        Duplicate/O Isas, $target 
     746                                        IF ( exists( "Idev" ) == 1 ) 
     747                                                target = "root:Idev_" + Run 
     748                                                Duplicate/O Idev, $target 
     749                                        ENDIF 
     750                                        IF ( exists( "Qdev" ) == 1 ) 
     751                                                target = "root:Qdev_" + Run 
     752                                                Duplicate/O Qdev, $target 
     753                                        ENDIF 
     754                                        IF ( exists( "dQw" ) == 1 ) 
     755                                                target = "root:QdQw_" + Run 
     756                                                Duplicate/O dQw, $target 
     757                                        ENDIF 
     758                                        IF ( exists( "dQl" ) == 1 ) 
     759                                                target = "root:dQl_" + Run 
     760                                                Duplicate/O dQl, $target 
     761                                        ENDIF 
     762                                        IF ( exists( "Qmean" ) == 1 ) 
     763                                                target = "root:Qmean_" + Run 
     764                                                Duplicate/O Qmean, $target 
     765                                        ENDIF 
     766                                        IF ( exists( "Shadowfactor" ) == 1 ) 
     767                                                target = "root:Shadowfactor_" + Run 
     768                                                Duplicate/O Shadowfactor, $target 
     769                                        ENDIF 
     770                                        target = "root:metadata_" + Run 
     771                                        Duplicate/O/T metadata, $target 
     772                                        BREAK 
     773                                ENDIF 
     774                        ENDFOR 
     775                ENDIF 
     776        ENDFOR 
     777 
     778        SetDataFolder root: 
     779END 
Note: See TracChangeset for help on using the changeset viewer.