Ignore:
Timestamp:
Mar 16, 2008 9:44:39 PM (14 years ago)
Author:
prjemian
Message:

added workaround to IgorPro? code for XML namespace differences on Mac and PC; propose a change to the standard XML header

File:
1 edited

Legend:

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

    r10 r12  
    11#pragma rtGlobals=1             // Use modern global access method. 
    2 #pragma version=1.01 
     2#pragma version=1.02 
    33 
    44// file:        cansasXML.ipf 
    55// author:      Pete R. Jemian <jemian@anl.gov> 
    6 // date:        2008-03-13 
     6// date:        2008-03-16 
    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 
     
    6262        XmlElemList(fileID)                                     // load the elementlist into W_ElementList 
    6363        WAVE/T  W_ElementList                           // This declaration comes _after_ XmlElemList() is called 
    64         CS_registerNameSpaces()                         // to assist XPath construction 
    65  
    66         // assume for now that canSAS namespace is constant throughout this XML 
    67         // call this code once here, rather many times throughout 
    68         STRING/G nsPre = "", nsStr = "" 
    69         nsPre = CS_GetKeyByNameSpace(W_ElementList[0][1]) 
    70         IF (strlen(nsPre) > 0)  
    71                 nsStr = nsPre + "=" + W_ElementList[0][1] 
    72                 nsPre += ":" 
    73         ENDIF 
    7464 
    7565        // qualify the XML file, don't allow just any ole XML. 
     
    8171                RETURN(-2)                                              // not a canSAS XML file 
    8272        ENDIF 
     73 
     74        // make an index to speed up searching through column 0 
     75        Make/O/T/N=(DimSize(W_ElementList, 0)) W_ElementList_Col0 
     76        W_ElementList_Col0 = W_ElementList[p][0] 
     77        STRING/G nsPre = "", nsStr = "" 
     78        CS_registerNameSpaces(fileID)                           // to assist XPath construction 
     79 
     80        // PRJ_quick(fileID) 
     81 
    8382        // identify supported versions of canSAS XML standard 
    8483        STRING version 
     
    123122        STRING/G Title, FolderList = "" 
    124123        STRING XPathStr, Title_folder, SASdata_folder 
     124        STRING SASentryPath, SASdataPath 
    125125        VARIABLE i, j, index, SASdata_index, returnCode = 0 
    126126 
     
    128128        CS_simpleXmlListXpath(fileID, "", "/SASroot//SASentry") 
    129129        WAVE/T  W_listXPath 
     130        // (safer to copy W_listxpath to a local variable and allow for other calls to XMLlistXpath) 
    130131        DUPLICATE/O/T   W_listXPath, SASentryList 
    131132 
     
    139140 
    140141        // process each SASentry element 
    141         // (safer to copy W_listxpath to a local variable and allow for other calls to XMLlistXpath) 
    142142        DUPLICATE/O/T metadata, metadata_file 
    143143        FOR (i = 0; i < numpnts(SASentryList); i += 1) 
    144144                index = CS_findElementIndex(SASentryList[i]) 
    145145                DUPLICATE/O/T metadata_file, metadata 
    146                 Title = CS_locateTitle(fileID, SASentryList[i])         // look in several places or use default title 
     146                Title = CS_1i_locateTitle(fileID, CS_correctedXpathStr(SASentryList[i]))                // look in several places or use default title 
    147147                Title_folder = CleanupName(Title, 0) 
    148148                IF ( CheckName(Title_folder, 11) != 0 ) 
     
    152152                FolderList = AddListItem(Title_folder, FolderList, ";", Inf) 
    153153                // 
    154                 CS_1i_collectMetadata(fileID, SASentryList[i]) 
     154                // CS_correctedXpathStr 
     155                SASentryPath = CS_correctedXpathStr(SASentryList[i]) 
     156                CS_1i_collectMetadata(fileID, SASentryPath) 
    155157                // 
    156158                // next, extract each SASdata block into a subfolder 
    157                 CS_simpleXmlListXpath(fileID, SASentryList[i], "//SASdata")     //output: W_listXPath 
     159                CS_simpleXmlListXpath(fileID, SASentryPath, "//SASdata")        //output: W_listXPath 
    158160                DUPLICATE/O/T   W_listXPath, SASdataList 
    159161                IF (numpnts(SASdataList) == 1) 
    160162                        // only one SASdata element, place data waves in Title folder 
     163                        SASdataPath = CS_correctedXpathStr(SASdataList[0]) 
    161164                        SASdata_folder = ":" + Title_folder + ":" 
    162165                        PRINT "\t\t dataFolder:", SASdata_folder 
    163                         IF (CS_1i_extractSasData(fileID, SASdataList[0], SASdata_folder)) 
     166                        IF (CS_1i_extractSasData(fileID, SASdataPath, SASdata_folder)) 
    164167                                // non-zero return code means an error, message is in errorMsg 
    165168                                // What to do now? 
     
    172175                                BREAK 
    173176                        ENDIF 
    174                         CS_appendMetaData(  "Run", "", CS_XmlStrFmXpath(fileID, SASdataList[0]+"/",  "../Run["+num2str(j+1)+"]")) 
    175                         CS_appendMetaData(  "Run_name", "", CS_XmlStrFmXpath(fileID, SASdataList[0]+"/",  "../Run["+num2str(j+1)+"]/@name")) 
    176                         CS_appendMetaData(  "SASdata_name", "", CS_XmlStrFmXpath(fileID, SASdataList[0],  "/@name")) 
     177                        CS_appendMetaData(  "Run", "", CS_XmlStrFmXpath(fileID, SASdataPath+"/",  "../Run["+num2str(j+1)+"]")) 
     178                        CS_appendMetaData(  "Run_name", "", CS_XmlStrFmXpath(fileID, SASdataPath+"/",  "../Run["+num2str(j+1)+"]/@name")) 
     179                        CS_appendMetaData(  "SASdata_name", "", CS_XmlStrFmXpath(fileID, SASdataPath,  "/@name")) 
    177180                ELSE 
    178181                        // multiple SASdata elements, place data waves in subfolders 
     
    180183                        FOR (j = 0; j < numpnts(SASdataList); j += 1) 
    181184                                DUPLICATE/O/T metadata_entry, metadata 
    182                                 XMLlistAttr(fileID,SASdataList[j],nsStr) 
    183                                 WAVE/T M_ListAttr 
    184185                                SASdata_index = CS_findElementIndex(SASdataList[j]) 
     186                                SASdataPath = CS_correctedXpathStr(SASdataList[j]) 
    185187                                SASdata_folder = CleanupName(StringByKey("name", W_ElementList[SASdata_index][2]), 0) 
    186188                                PRINT "\t\t dataFolder:", SASdata_folder 
    187                                 CS_appendMetaData(  "Run"+num2str(j), "", CS_XmlStrFmXpath(fileID, SASdataList[j]+"/",  "../Run["+num2str(j+1)+"]")) 
    188                                 CS_appendMetaData(  "Run"+num2str(j)+"_name", "", CS_XmlStrFmXpath(fileID, SASdataList[j]+"/",  "../Run["+num2str(j+1)+"]/@name")) 
    189                                 CS_appendMetaData(  "SASdata"+num2str(j)+"_name", "", CS_XmlStrFmXpath(fileID, SASdataList[j],  "/@name")) 
     189                                CS_appendMetaData(  "Run"+num2str(j), "", CS_XmlStrFmXpath(fileID, SASdataPath+"/",  "../Run["+num2str(j+1)+"]")) 
     190                                CS_appendMetaData(  "Run"+num2str(j)+"_name", "", CS_XmlStrFmXpath(fileID, SASdataPath+"/",  "../Run["+num2str(j+1)+"]/@name")) 
     191                                CS_appendMetaData(  "SASdata"+num2str(j)+"_name", "", CS_XmlStrFmXpath(fileID, SASdataPath,  "/@name")) 
    190192                                SetDataFolder $Title_folder 
    191193                                IF ( CheckName(SASdata_folder, 11) != 0 ) 
     
    196198                                SASdata_folder =  ":" + Title_folder + ":" + SASdata_folder + ":" 
    197199                                //--- 
    198                                 IF (CS_1i_extractSasData(fileID, SASdataList[j], SASdata_folder)) 
     200                                IF (CS_1i_extractSasData(fileID, SASdataPath, SASdata_folder)) 
    199201                                        // non-zero return code means an error, message is in errorMsg 
    200202                                        // What to do now? 
     
    326328// ================================================================== 
    327329 
    328 FUNCTION/S CS_locateTitle(fileID, SASentryPath) 
     330FUNCTION/S CS_1i_locateTitle(fileID, SASentryPath) 
    329331        VARIABLE fileID 
    330332        STRING SASentryPath 
     
    387389 
    388390FUNCTION CS_findElementIndex(matchStr) 
     391        STRING matchStr 
    389392        // 
    390393        // support the canSAS XML file reader 
    391         // return index where   W_ElementList[index][0] == matchStr 
     394        // return index where   g[index][0] == matchStr 
    392395        // return -1 if not found 
    393396        // 
    394         // not dependent on the version of the canSAS XML file being read 
    395         // 
     397        WAVE/T W_ElementList_Col0 
     398 
     399        FindValue/TEXT=matchStr    W_ElementList_Col0 
     400        RETURN(V_value) 
     401END 
     402 
     403// ================================================================== 
     404 
     405FUNCTION CS_registerNameSpaces(fileID) 
     406        VARIABLE fileID 
     407        // 
     408        // Only one namespace might be used within the document and that is 
     409        // the one defined in the zzz:schemaLocation attribute to the <SASroot> element. 
     410        // Since the XMLutils XOP only extracts the schemaLocation as an attribute, 
     411        // we just ask for "/*/@schemaLocation" and pick the first URI as the namespace. 
     412        // We can use our own namespace prefix without further concern. 
     413        // 
     414        WAVE/T W_ElementList 
     415        SVAR nsPre 
     416        SVAR nsStr 
     417        VARIABLE i, j, index 
     418        STRING testStr 
     419        // 
     420        nsStr = StringFromList(0, StringByKey("schemaLocation", W_ElementList[0][2]), " ") 
     421        nsStr = W_ElementList[0][1]             // this is the one to use 
     422        IF (strlen(nsStr)) 
     423                nsPre = "cs:" 
     424                nsStr = "cs=" + nsStr 
     425        ELSE 
     426                nsPre = "" 
     427        ENDIF 
     428 
     429        // 2008-03-14,PRJ: Now, add a workaround for the libxml2 support that affects MacOS. 
     430        //   When using namespaces  
     431        //              W_ElementList[][1] != "" (it shows a namespace for this node) 
     432        //   and with default libxml2 (v2.2) on MacOS, 
     433        //              W_ElementList[][0] != /SASroot/SASentry ... 
     434        //  BUT, on PCs and on MacOS with user-proveded libxml2 (?version?) 
     435        //              W_ElementList[][0] != /*/*[1]   or /*/* ... 
     436        // 
     437        // Need to handle either situation. 
     438        //  Add another column to W_ElementList that shows the corrected absolute  
     439        //      XPath query,  complete with namespace prefix as needed. 
     440        Redimension/N=(DimSize(W_ElementList,0),5) W_ElementList 
     441        W_ElementList[0,Inf][4] = ""                            // clear out the last column (useful only to developer) 
     442        W_ElementList[0][4] = CS_XPath_NS("/"+W_ElementList[0][3]) 
     443        FOR (i = 1; i < DimSize(W_ElementList,0); i += 1) 
     444                IF (strlen(W_ElementList[i][4]) == 0)           // if not already set, then find absolute XPath string 
     445                        index = CS_findElementIndex(  CS_findLast(W_ElementList[i][0], "/", 1  )  ) 
     446                        testStr = W_ElementList[index][4] + CS_XPath_NS("/"+W_ElementList[i][3]) 
     447                        XMLlistXpath(fileID,testStr,nsStr) 
     448                        WAVE/T W_listXPath 
     449                        SWITCH(numpnts(W_listXPath)) 
     450                                CASE 0:                 // What?  Can't find the node we just found? 
     451                                        PRINT numpnts(W_listXPath), testStr, " !!! WARNING:  <Can't find the node we just found> in CS_registerNameSpaces()" 
     452                                        BREAK 
     453                                CASE 1:                 // Only one node with this element 
     454                                        W_ElementList[i][4] = testStr 
     455                                        BREAK 
     456                                DEFAULT:                        // Multiple elements match this node; need to use indices 
     457                                        // PRINT numpnts(W_listXPath), testStr 
     458                                        FOR (j = 0; j < numpnts(W_listXPath); j += 1) 
     459                                                index = CS_findElementIndex(  W_listXPath[j]  ) 
     460                                                W_ElementList[index][4] = testStr + "[" + num2str(j+1) + "]" 
     461                                        ENDFOR 
     462                                        BREAK 
     463                        ENDSWITCH 
     464                ENDIF 
     465        ENDFOR 
     466        // PRINT StringByKey("schemaLocation", W_ElementList[0][2]) 
     467        // 
     468        // <code comes here> 
     469        RETURN(0) 
     470END 
     471 
     472// ================================================================== 
     473 
     474FUNCTION/S CS_findLast(src, matchStr, leftSide) 
     475        STRING src 
    396476        STRING matchStr 
    397         WAVE/T W_ElementList 
     477        VARIABLE leftSide 
     478        // given a source string such as:   /*/*/*[7]/*/*[39]/*[2] 
     479        // return the part on the $leftSide if the $matchStr 
     480        // Examples: 
     481        //       CS_findLast( "/*/*/*[7]/*/*[39]/*[2]"  , "/", 1)                 /*/*/*[7]/*/*[39] 
     482        //       CS_findLast( "/*/*/*[7]/*/*[39]/*[2]"  , "/", 0)                 /*[2] 
     483        //       CS_findLast( "/*/*/*[7]/*/*[39]/*[2]"  , "[", 1)                 /*/*/*[7]/*/*[39]/* 
     484        //       CS_findLast( "/*/*/*[7]/*/*[39]/*[2]"  , "[", 0)                 [2] 
    398485        VARIABLE i 
    399         FOR (i = 0; i < numpnts(W_ElementList); i += 1) 
    400                 IF ( CmpStr(W_ElementList[i][0], matchStr)  == 0 ) 
    401                         RETURN(i) 
     486        STRING result="", test 
     487        FOR (i=strlen(src)-1; i >= 0; i -= 1) 
     488                IF (stringmatch(src[i], matchStr )) 
     489                        IF (leftSide) 
     490                                result = src[0,i-1] 
     491                        ELSE 
     492                                result = src[i,Inf] 
     493                        ENDIF 
     494                        RETURN(result) 
    402495                ENDIF 
    403496        ENDFOR 
    404         RETURN(-1) 
    405 END 
    406  
    407 // ================================================================== 
    408  
    409 FUNCTION CS_registerNameSpaces() 
    410         // 
    411         // identify the namespaces in use by the XML file described in W_ElementList 
    412         // build a registry for later use that assigns a prefix to each unique namespace 
    413         // build a reverse registry as well to identify the keyword 
    414         // 
    415         WAVE/T W_ElementList 
    416         STRING thisNs 
    417         STRING thisKey = "ns" 
    418         STRING/G nsRegistry = "" 
    419         STRING/G reverseRegistry = "" 
    420         STRING/G keySep = "=", listSep = ";" 
    421         VARIABLE i 
    422         // first, identify all the namespaces in use by looking at  W_ElementList[][1] 
    423         FOR (i = 0; i < numpnts(W_ElementList); i += 1) 
    424                 thisNs = W_ElementList[i][1] 
    425                 // value does not matter now, we'll fix that later 
    426                 reverseRegistry = ReplaceStringByKey(thisNs, reverseRegistry, thisKey, keySep, listSep) 
    427         ENDFOR 
    428         // next, create the registry by indexing each namespace 
    429         FOR (i = 0; i < ItemsInList(reverseRegistry, listSep); i += 1) 
    430                 thisNs = StringFromList(0, StringFromList(i, reverseRegistry, listSep), keySep) 
    431                 thisKey = "ns" + num2str(i) 
    432                 nsRegistry = ReplaceStringByKey(thisKey, nsRegistry, thisNs, keySep, listSep) 
    433                 // don't forget to assign the proper key name as the value in the reverse registry 
    434                 reverseRegistry = ReplaceStringByKey(thisNs, reverseRegistry, thisKey, keySep, listSep) 
    435         ENDFOR 
    436         RETURN(0) 
    437 END 
    438  
    439 // ================================================================== 
    440  
    441 FUNCTION/S CS_GetNameSpaceByKey(key) 
    442         STRING key 
    443         STRING ns 
    444         SVAR nsRegistry 
    445         SVAR keySep 
    446         SVAR listSep 
    447         ns = StringByKey(key, nsRegistry, keySep, listSep) 
    448         RETURN(ns) 
    449 END 
    450  
    451 // ================================================================== 
    452  
    453 FUNCTION/S CS_GetKeyByNameSpace(ns) 
    454         STRING ns 
    455         STRING key 
    456         SVAR reverseRegistry 
    457         SVAR keySep 
    458         SVAR listSep 
    459         key = StringByKey(ns, reverseRegistry, keySep, listSep) 
    460         RETURN(key) 
     497        RETURN(result) 
    461498END 
    462499 
     
    491528// ================================================================== 
    492529 
    493 FUNCTION/S CS_buildXpathStr(prefix, value) 
    494         STRING prefix, value 
    495         SVAR nsPre 
    496         STRING XPathStr = "" 
    497         // namespaces complicate the XPath description 
    498         // this function can be used only with very simple XPath constructions 
    499         IF (strlen(nsPre) > 0)  
    500                 XPathStr = prefix + nsPre + value 
    501         ELSE 
    502                 XPathStr = prefix + value 
    503         ENDIF 
    504         RETURN(XPathStr) 
    505 END 
    506  
    507 // ================================================================== 
    508  
    509530FUNCTION/S CS_XmlStrFmXpath(fileID, prefix, value) 
    510531        VARIABLE fileID 
     
    524545        XMLwaveFmXpath(fileID, prefix + CS_XPath_NS(value), nsStr, " ")  
    525546        // output: M_xmlContent  W_xmlContentNodes 
     547END 
     548 
     549// ================================================================== 
     550 
     551FUNCTION/S CS_correctedXpathStr(indexPath) 
     552        STRING indexPath 
     553        VARIABLE index 
     554        STRING absolutePath 
     555        WAVE/T          W_ElementList 
     556        index  =  CS_findElementIndex(indexPath) 
     557        absolutePath = W_ElementList[index][4]  // use corrected XPath string 
     558        RETURN(absolutePath) 
    526559END 
    527560 
     
    751784                theFile = StringFromList(i, fList)                                      // walk through all test files 
    752785                // PRINT "file: ", theFile 
    753                 IF (CS_XmlReader(theFile) == 0)                                 // did the XML reader return without an error code? 
     786                pathInfo home  
     787                //IF (CS_XmlReader(theFile) == 0)                                       // did the XML reader return without an error code? 
     788                IF (CS_XmlReader(ParseFilePath(5,S_path,"*",0,0) + theFile) == 0)    // did the XML reader return without an error code? 
    754789                        prj_grabMyXmlData()                                             // move the data to my directory 
    755790                ENDIF 
    756791        ENDFOR 
    757792END 
     793 
     794// ================================================================== 
     795 
     796FUNCTION PRJ_quick(fileID) 
     797        VARIABLE fileID 
     798        WAVE/T W_ElementList, W_listXPath 
     799        SVAR nsStr 
     800 
     801        XMLlistXpath(fileID, "/cs:SASroot/cs:SASentry/cs:Title", nsStr)         // output: W_listXPath 
     802        print W_listXPath[0] 
     803        XMLlistXpath(fileID, "//cs:Idata[4]", nsStr)            // output: W_listXPath 
     804        print W_listXPath[0] 
     805        XMLlistXpath(fileID, "//cs:Idata*", nsStr)              // output: W_listXPath 
     806        print W_listXPath[0] 
     807        XMLlistXpath(fileID, "//cs:Idata", nsStr)               // output: W_listXPath 
     808        print W_listXPath[0] 
     809        XMLlistXpath(fileID, "/cs:SASroot/cs:SASentry/cs:SASdata/cs:Idata[4]", nsStr)           // output: W_listXPath 
     810        print W_listXPath[0] 
     811        XMLlistXpath(fileID, "/*/@*", "")               // output: W_listXPath 
     812        print W_listXPath[0] 
     813        PRINT TrimWS(XmlStrFmXpath(fileID, "/*/@version", "", "")) 
     814        PRINT TrimWS(XmlStrFmXpath(fileID, "/*/@xmlns", "", "")) 
     815        PRINT StringByKey("schemaLocation", W_ElementList[0][2]) 
     816 
     817        //CS_simpleXmlListXpath(fileID, "", "/SASroot//SASentry") 
     818        //WAVE/T        W_listXPath 
     819        //DUPLICATE/O/T   W_listXPath, SASentryList 
     820 
     821        //<SASroot version="1.0" 
     822        //      xmlns="http://www.smallangles.net/cansas1d" 
     823        //      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     824        //      xsi:schemaLocation="http://www.smallangles.net/cansas1d/ http://www.smallangles.net/cansas1d/1.0/cansas1d.xsd" 
     825        //      > 
     826 
     827 
     828END 
Note: See TracChangeset for help on using the changeset viewer.