Skip to content

Macro SMILE_ODS_DOCUMENT_FLAT_LABEL

Flat navigation and optionally re-label navigation for ODS DOCUMENT. The navigation bookmark level is reduced to one level only. Optionally a label can be applied to all content items or the navigation label can be removed completely.

  • Author: Katja Glass
  • Date: 2021-02-15
  • SAS Version: SAS 9.4
  • License: MIT
  • Comment: The navigation in PDF documents can be one level only with this macro. CONTENTS="" must be applied to the PROC REPORT as option and additionally for a BREAK BEFORE PAGE option.
  • Issues: The table of contents created per default by SAS (ODS PDF option TOC) is not linking the pages correctly when using BY groups and having one ODS DOCUMENT with multiple outputs, using single ODS DOCUMENTS (one per each output) then this is working correctly. In such a case, do use not a TOC or create an own TOC, e.g. like described here: https://www.mwsug.org/proceedings/2012/S1/MWSUG-2012-S125.pdf
  • Reference: A nice overview of ODS DOCUMENT can be found here: https://support.sas.com/resources/papers/proceedings12/273-2012.pdf
  • Example Program: test_smile_ods_document_flat_label

Parameters

Parameter Description
DOCUMENT ODS Document item store
LABEL One label to apply on first element, all other labels are removed (optional), if not provided, labels are just rearranged and additional BY-labels removed
BOOKMARKLABEL Indicator whether to use Bookmark Labels if none is specified (YES Default), if LABEL is missing and BOOKMARKLABEL = NO, all labels are removed


Examples

%*This will flatten the navigation and use the labels originally set with ODS PROCLABEL;
%smile_ods_document_flat_label(document=doc_reports);

%*This will flatten the navigation and use the label "Table 1.1.1" applied to all items of this store;
%smile_ods_document_flat_label(document=doc_report1, label=Table 1.1.1);

%*This will flatten the navigation and use no navigation label at all (no navigation link at all for these items);
%smile_ods_document_flat_label(document=doc_report1, label=, bookmarklabel = NO);

Checks

  • DOCUMENT must be specified;
  • BOOKMARKLABEL must be YES or NO;
  • DOCUMENT must contain content;

Macro

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
%************************************************************************************************************************;
%* Project    : SMILE - SAS Macros, Intuitive Library Extension
%* Macro      : smile_ods_document_flat_label
%* Parameters : DOCUMENT      - ODS Document item store
%*              LABEL         - One label to apply on first element, all other labels are removed (optional),
%*                              if not provided, labels are just rearranged and additional BY-labels removed
%*              BOOKMARKLABEL - Indicator whether to use Bookmark Labels if none is specified (YES Default),
%*                              if LABEL is missing and BOOKMARKLABEL = NO, all labels are removed
%*
%* Purpose    : Flat navigation and optionally re-label navigation for ODS DOCUMENT. The navigation bookmark level is
%*              reduced to one level only. Optionally a label can be applied to all content items or the navigation label
%*              can be removed completely.
%* Comment    : The navigation in PDF documents can be one level only with this macro. CONTENTS="" must be applied to
%*              the PROC REPORT as option and additionally for a BREAK BEFORE PAGE option.
%* Issues     : The table of contents created per default by SAS (ODS PDF option TOC) is not linking the pages correctly when
%*              using BY groups and having one ODS DOCUMENT with multiple outputs, using single ODS DOCUMENTS (one per each output)
%*              then this is working correctly. In such a case, do use not a TOC or create an own TOC, e.g. like described here:
%*              https://www.mwsug.org/proceedings/2012/S1/MWSUG-2012-S125.pdf
%*
%* ExampleProg: ../programs/test_smile_ods_document_flat_label.sas
%*
%* Author     : Katja Glass
%* Creation   : 2021-02-15
%* License    : MIT
%*
%* Reference  : A nice overview of ODS DOCUMENT can be found here: https://support.sas.com/resources/papers/proceedings12/273-2012.pdf
%*
%* SAS Version: SAS 9.4
%*
%************************************************************************************************************************;
/*
Examples:
%*This will flatten the navigation and use the labels originally set with ODS PROCLABEL;
%smile_ods_document_flat_label(document=doc_reports);

%*This will flatten the navigation and use the label "Table 1.1.1" applied to all items of this store;
%smile_ods_document_flat_label(document=doc_report1, label=Table 1.1.1);

%*This will flatten the navigation and use no navigation label at all (no navigation link at all for these items);
%smile_ods_document_flat_label(document=doc_report1, label=, bookmarklabel = NO);
*/
%************************************************************************************************************************;

%MACRO smile_ods_document_flat_label(document=, label=, bookmarkLabel = yes);

   %LOCAL macro _temp;
   %LET macro = &sysmacroname;
   %LET _temp = -1;

%*;
%* Error handling I;
%*;

   %* check: DOCUMENT must be specified;
   %IF %LENGTH(&document) = 0
   %THEN %DO;
       %PUT %STR(ERR)OR: &macro - DOCUMENT parameter is required. Macro will abort;
       %RETURN;
   %END;

   %* check: BOOKMARKLABEL must be YES or NO;
   %IF %UPCASE(&bookmarkLabel) NE YES AND %UPCASE(&bookmarkLabel) NE NO
   %THEN %DO;
       %PUT %STR(ERR)OR: &macro - BOOKMARKLABEL parameter must either be NO or YES. Macro will abort;
       %RETURN;
   %END;

   %* check - DOCUMENT must be an existing item store in WORK;
   PROC SQL NOPRINT;
       SELECT 1 INTO :_temp FROM SASHELP.VMEMBER
           WHERE libname="WORK" AND memname="%UPCASE(&document)" AND memtype = "ITEMSTOR";
   RUN;QUIT;
   %IF &_temp NE 1
   %THEN %DO;
       %PUT %STR(ERR)OR: &macro - DOCUMENT (&document) is no existing ODS DOCUMENT. Macro will abort;
       %RETURN;
   %END;

%*;
%* Read information;
%*;

   ODS SELECT NONE;
   PROC DOCUMENT NAME = &document;
       LIST / DETAILS LEVELS=all;
       ODS OUTPUT PROPERTIES = _props;
   RUN;QUIT;
   ODS SELECT ALL;

%*;
%* Error handling II;
%*;

   %* check: DOCUMENT must contain content;
   %LET _temp = -1;
   PROC SQL NOPRINT;
       SELECT nobs INTO :_temp FROM SASHELP.VTABLE WHERE libname="WORK" AND memname="_PROPS";
   RUN;QUIT;
   %IF &_temp = 0
   %THEN %DO;
       %PUT %STR(WAR)NING: &macro - DOCUMENT (&document) does not contain any observations - no action done;
       %RETURN;
   %END;

%*;
%* Processing;
%*;

   %* create a generic processing for PROC DOCUMENT;
   %* Step 1: move all reports to /all and apply label;
   DATA _NULL_;
       SET _props END=_eof;
       ATTRIB coreLabel FORMAT=$200.;
       RETAIN coreLabel;
       RETAIN _count 1 _first 0 _core 0;

       IF _N_ = 1
       THEN DO;
           CALL EXECUTE("PROC DOCUMENT NAME=&document;");
       END;

       IF COUNT(path,"\") = 1 AND type = "Dir"
       THEN DO;
           _core = 1;
           %IF %UPCASE(&bookmarkLabel) NE YES
           %THEN %DO;
               CALL MISSING(coreLabel);
               PUT "updateOdsDocument - No label is used";
           %END;
           %ELSE %IF %LENGTH("&label") > 2
           %THEN %DO;
               coreLabel = "&label";
           %END;
           %ELSE %DO;
               coreLabel = label;
               _first = 0;

           %END;
       END;

       IF type NE "Dir" AND _core
       THEN DO;
           CALL EXECUTE('MOVE ' || STRIP(path) || ' to \all;');
           IF _first = 0
               THEN CALL EXECUTE('SETLABEL \all#' || STRIP(PUT(_count,BEST.)) || " '" || STRIP(coreLabel) || "';");
           _first = 1;
           _count = _count + 1;
       END;

       IF _eof
       THEN DO;
           CALL EXECUTE('RUN;QUIT;');
       END;
   RUN;

   %* Step 2: remove all old hierarchies;
   DATA _NULL_;
       SET _props END=_eof;
       IF _N_ = 1
           THEN CALL EXECUTE("PROC DOCUMENT NAME=&document;");
       IF COUNT(path,"\") = 1 AND type = "Dir"
           THEN CALL EXECUTE('DELETE ' || STRIP(path) || ";");
       IF _eof
           THEN CALL EXECUTE('RUN;QUIT;');
   RUN;

%*;
%* Cleanup;
%*;

   PROC DATASETS LIB=WORK;
       DELETE _props;
   RUN;

%MEND smile_ods_document_flat_label;