<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Names of Excel sheets in SAS Programming</title>
    <link>https://communities.sas.com/t5/SAS-Programming/Names-of-Excel-sheets/m-p/415799#M102044</link>
    <description>&lt;P&gt;Nice share,&lt;/P&gt;
&lt;P&gt;I assume this is not a question, so I will nominate it as library contribution.&lt;/P&gt;</description>
    <pubDate>Thu, 23 Nov 2017 11:41:34 GMT</pubDate>
    <dc:creator>LinusH</dc:creator>
    <dc:date>2017-11-23T11:41:34Z</dc:date>
    <item>
      <title>Names of Excel sheets</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Names-of-Excel-sheets/m-p/415626#M101951</link>
      <description>&lt;P&gt;A user asked me if it is possible to manipulate the data in the FIRST sheet like this:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;data xlsxdata.&amp;lt;name&amp;gt;;
    set xlsxdata.&amp;lt;name&amp;gt;;
    ...
    do something
    ...
run;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;The problem is: The name of the first sheet may vary - so what to write in &amp;lt;name&amp;gt;?&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Let's say the sheets look like this - "Thematic" is the first sheet:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Screen Shot 11-22-17 at 07.32 PM.PNG" style="width: 310px;"&gt;&lt;img src="https://communities.sas.com/t5/image/serverpage/image-id/16803i36E1F4576195CEB9/image-size/large?v=v2&amp;amp;px=999" role="button" title="Screen Shot 11-22-17 at 07.32 PM.PNG" alt="Screen Shot 11-22-17 at 07.32 PM.PNG" /&gt;&lt;/span&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;The first approach to get the name is via an EXCEL libname and PROC DATASETS/DICTIONARY TABLES. Unfortunately the sheet names are ordered alphabetically - you cannot decide which one is the first:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;                      DBMS
              Member  Member
#  Name       Type    Type

1  Details$   DATA    TABLE
2  Summary$   DATA    TABLE
3  Thematic$  DATA    TABLE
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;Well, an xlsx file is also a zip file made up of several xml files. The "workbook.xml" in the xl folder has the wanted information:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;&amp;lt;sheet r:id="rId1" sheetId="1" name="Thematic"/&amp;gt;
&amp;lt;sheet r:id="rId2" sheetId="2" name="Summary"/&amp;gt;
&amp;lt;sheet r:id="rId3" sheetId="3" name="Details"/&amp;gt;&lt;BR /&gt;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;That's great because we know that SAS is able to read an xml file - perhaps using an xml map. And the really big thing is that we can do it automatically:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;/* read and create xml-file in the WORK folder  */
filename _WRKBOOK ZIP "H:\test it now\test.xlsx" member='xl/workbook.xml';
filename _XMLFIL      "%sysfunc(pathname(WORK))\workbook.xml";

data _null_;
    infile _WRKBOOK recfm=n ;
    file   _XMLFIL   recfm=n;
    input char $char1. @@;
    put char $char1. @@;
run;

/* Assign a xml LIBNAME and do an automap */
filename  _SXLEMAP "%sysfunc(pathname(WORK))\xmlmap.map";
libname   _XMLFIL xmlv2 automap=replace xmlmap=_SXLEMAP access=READONLY;

/* The SHEET table contains the sheet names */
data _null_;
    set _xmlfil.sheet (obs=1);
    call symputx("SHEET",sheet_name);
run;

/* de-assign */
filename _WRKBOOK;
filename _SXLEMAP;
filename _XMLFIL;
libname  _XMLFIL;
&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;and the happy user now has the solution:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;libname xlsxdata XLSX "H:\test it now\test.xlsx";&lt;BR /&gt;&lt;BR /&gt;data xlsxdata."&amp;amp;SHEET"n;
    set xlsxdata."&amp;amp;SHEET"n;&lt;BR /&gt;    &amp;lt;manipulations here&amp;gt;&lt;BR /&gt;run;&lt;BR /&gt;libname xlsxdata;&lt;BR /&gt;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;The only downside is the rather hefty intro so an idea is to wrap this up in a SAS Macro: SHEETNAMES. The macro generates macro variables SHEET1, SHEET2, etc. with the sheet names and the number of sheets, SHEETS, just in case:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%macro sheetnames(xlsxfile=);
    options nonotes nosource;

    %if NOT %sysfunc(fileexist(&amp;amp;xlsxfile)) %then %do;
        %put ERROR: File %upcase(&amp;amp;xlsxfile) does not exist.;
        options source notes;
        %return;
    %end;

    /* read and create xml-file in the WORK folder  */
    filename _WRKBOOK ZIP "&amp;amp;xlsxfile" member='xl/workbook.xml';
    filename _XMLFIL      "%sysfunc(pathname(WORK))\workbook.xml";

    data _null_;
        infile _WRKBOOK recfm=n ;
        file   _XMLFIL   recfm=n;
        input char $char1. @@;
        put char $char1. @@;
    run;

    /* Assign a xml LIBNAME and do a automap */
    filename  _SXLEMAP "%sysfunc(pathname(WORK))\xmlmap.map";
    libname   _XMLFIL xmlv2 automap=replace xmlmap=_SXLEMAP access=READONLY;

    /* The SHEET table contains the sheet names */
    data _null_;
        set _xmlfil.sheet end=finish;
        call symputx(cats("SHEET",_n_),sheet_name,'G');
        if finish then
            call symputx("SHEETS",_n_,'G');
    run;

    /* de-assign */
    filename _WRKBOOK;
    filename _SXLEMAP;
    filename _XMLFIL;
    libname  _XMLFIL;

    options notes source;
%mend;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;The users code is now pretty compact:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;PRE&gt;&lt;CODE class=" language-sas"&gt;%sheetnames(xlsxfile=H:\test it now\test.xlsx);&lt;BR /&gt;&lt;BR /&gt;libname xlsxdata XLSX "H:\test it now\test.xlsx";&lt;BR /&gt;&lt;BR /&gt;data xlsxdata."&amp;amp;SHEET1"n;
    set xlsxdata."&amp;amp;SHEET1"n;&lt;BR /&gt;    &amp;lt;manipulations here&amp;gt;&lt;BR /&gt;run;&lt;BR /&gt;libname xlsxdata;&lt;BR /&gt;&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;What are the points:&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;An xlsx file can be treated as a zip file - easy to read SOME information with FILENAME and ZIP engine&lt;/LI&gt;
&lt;LI&gt;You can do an automap in the XMLV2 LIBNAME - no need for the XML Mapper.&lt;/LI&gt;
&lt;/OL&gt;
&lt;P&gt;&amp;nbsp;Have a nice day &lt;span class="lia-unicode-emoji" title=":winking_face:"&gt;😉&lt;/span&gt;&lt;/P&gt;</description>
      <pubDate>Wed, 22 Nov 2017 19:37:13 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Names-of-Excel-sheets/m-p/415626#M101951</guid>
      <dc:creator>PeterKellberg</dc:creator>
      <dc:date>2017-11-22T19:37:13Z</dc:date>
    </item>
    <item>
      <title>Re: Names of Excel sheets</title>
      <link>https://communities.sas.com/t5/SAS-Programming/Names-of-Excel-sheets/m-p/415799#M102044</link>
      <description>&lt;P&gt;Nice share,&lt;/P&gt;
&lt;P&gt;I assume this is not a question, so I will nominate it as library contribution.&lt;/P&gt;</description>
      <pubDate>Thu, 23 Nov 2017 11:41:34 GMT</pubDate>
      <guid>https://communities.sas.com/t5/SAS-Programming/Names-of-Excel-sheets/m-p/415799#M102044</guid>
      <dc:creator>LinusH</dc:creator>
      <dc:date>2017-11-23T11:41:34Z</dc:date>
    </item>
  </channel>
</rss>

