BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
bnawrocki
Quartz | Level 8

I'm trying to create a cool search-and-filter HTML menu using JQuery Mobile code, similar to the one under the Listviews heading here: http://demos.jquerymobile.com/1.4.5/intro/. I'm writing SAS 9.4 code to create the HTML/jQuery output file. I want to fill the values of the list from the NAME column of my NAMES SAS dataset.

 

This SAS code to generate the list almost works.

 

%macro printNames();

  proc sql noprint;
     select count(*) into :numRecs
	 from names;
  quit;
  %do i = 1 %to &numRecs;
    data _null_;
	  choice = &i;
      set names point=choice;
	  call symput('name', trim(name));
	  stop;
    run;
	data _null_;
	  ods html3 text= "<li><a href='#'>&name</a></li>";
	run;
  %end;
%mend printNames;

... but each time I call "ods html3" it triggers the paragraph event, and surrounds my <li>...</li> output with <p> and </p> tags. This puts extra spacing between the list items, which looks bad. I want to find a way to stop those <p> and </p> tags from printing.

 

After some digging, I found I can override an event - this "paragraph" event - by writing some PROC TEMPLATE code, like this. I'm removing the "<p>" and "</p>" tags and replacing them with just NL (new-line) commands.

 

proc template;
  define tagset tagsets.mytags;
    parent=????;
	define event paragraph;
         start:
            put NL;
            put VALUE; 
         finish:
put NL; end; end; run;

But what "parent" tagset do I need to override (replacing the ???? in code above)? What tagset does ODS HTML3 use? And how do I specify that I want to use my new tagset instead?

1 ACCEPTED SOLUTION

Accepted Solutions
Tim_SAS
Barite | Level 11

I wanted to make sure I hadn't given you bad guidance, so I tried this myself. I used the eventmap tagset to determine that ODS TEXT= strings are surrounded by three events: text_group, text_row, and text. The "value" event attribute in the text event contains the actual TEXT= string. By default those three events add <table>, <tr>, and <td> tags to the html, creating a table with one row and one cell. The cell contains the TEXT= string.

 

Here's code that captures all three of these events and substitutes some debugging output. Run it and examine the test.html file. (I did this with SAS 9.4M3.)

 

proc template;
	define tagset tagsets.mytagset;
		parent = tagsets.html4;

		define event text_group;
			start:
				put 'text_group event start' nl;
				ndent;
			finish:
				xdent;
				put 'text_group event finish' nl;
		end;

		define event text_row;
			start:
				put 'text_row event start' nl;
				ndent;
			finish:
				xdent;
				put 'text_row event finish' nl;
		end;

		define event text;
			start:
				put 'text event start' nl;
				ndent;
				put 'value=' value nl;
			finish:
				xdent;
				put 'text event finish' nl;
		end;
	end;
run;

ods tagsets.mytagset file="test.html";
ods text = "My text string";
ods text = "Another text string";
proc print data=sashelp.class;
run;
ods tagsets.mytagset close;

 

 

View solution in original post

7 REPLIES 7
Tim_SAS
Barite | Level 11

The HTML3 destination does not use a tagset. The HTML4 destination does use a tagset. In the SASHELP.TMPLMST template store, it's Tagsets.HTML4.

bnawrocki
Quartz | Level 8

I did see the HTML4 tagset in SASHELP.TMPLMAST and didn't know how or when it was used. It doesn't have a PARAGRAPH event for me to override, though. I think the PARAGRAPH event with the <p> </p> tags is in the Chtml tagset, so I'll try to override that one.

Tim_SAS
Barite | Level 11

The HTML4 tagset is the default when you specify the HTML destination in SAS 9.4. You can change the default in the SAS registry, but I'm assuming you haven't done that.

 

I see the paragraph event handler in tagsets.phtml, which is the parent of tagsets.htmlcss, which is the parent of tagsets.html4. However, instead of altering any of these tagsets, consider creating your own custom tagset. Use tagsets.html4 as the parent and your custom paragraph event handler as the only content. On your ODS statement, specify tagsets.mycustomhtml as the destination instead of HTML.

bnawrocki
Quartz | Level 8

Well, I tried a variety of ODS statements, from ODS HTML3 to ODS HTML5 to ODS MARKUP, but I could never figure out how to override the paragraph event that the ODS TEXT= statement initiates. I finally tried a different approach that worked, based on a suggestion to this other SAS Community question - Generate a totally raw HTML file.

 

I replaced all my ODS statements with a FILENAME statement followed by DATA _NULL_ steps with PUT statements that write all my HTML tags directly to the .html file. It's a brute force approach, but it worked for me

Cynthia_sas
SAS Super FREQ
Hi: If you know the DATA _NULL_ way of coding, that might be your best bet. Otherwise, to override the paragraph event, you would have needed to customize your own TAGSET template for HTML4 or HTML5 destinations.

cynthia
Tim_SAS
Barite | Level 11

I wanted to make sure I hadn't given you bad guidance, so I tried this myself. I used the eventmap tagset to determine that ODS TEXT= strings are surrounded by three events: text_group, text_row, and text. The "value" event attribute in the text event contains the actual TEXT= string. By default those three events add <table>, <tr>, and <td> tags to the html, creating a table with one row and one cell. The cell contains the TEXT= string.

 

Here's code that captures all three of these events and substitutes some debugging output. Run it and examine the test.html file. (I did this with SAS 9.4M3.)

 

proc template;
	define tagset tagsets.mytagset;
		parent = tagsets.html4;

		define event text_group;
			start:
				put 'text_group event start' nl;
				ndent;
			finish:
				xdent;
				put 'text_group event finish' nl;
		end;

		define event text_row;
			start:
				put 'text_row event start' nl;
				ndent;
			finish:
				xdent;
				put 'text_row event finish' nl;
		end;

		define event text;
			start:
				put 'text event start' nl;
				ndent;
				put 'value=' value nl;
			finish:
				xdent;
				put 'text event finish' nl;
		end;
	end;
run;

ods tagsets.mytagset file="test.html";
ods text = "My text string";
ods text = "Another text string";
proc print data=sashelp.class;
run;
ods tagsets.mytagset close;

 

 

bnawrocki
Quartz | Level 8

Thanks, Tim_SAS! With your suggestion, I was able to get my program working with ODS statements. It's also working in a slightly different version using the DATA _NULL_ and PUT statements method I mentioned above. Not sure which way I prefer, but at least I have the option.

 

The thing that was confusing me was that I was assuming the Paragraph event was being triggered, but it wasn't - based on your analysis, it was the Text_group, Text_row and Text events. I didn't realize you could determine the events that were triggered by using the eventmap tagset. I'll have to look up how to use the eventmap tagset sometime.

 

Anyway, the ODS code that works is this (basically, I'm nullifying the Text_group, Text_row and Text events, so I'm only writing the "value" from my ODS TEXT= statement):

proc template;
  define style styles.test;
  parent=styles.default;
  style body from body /
    prehtml='<meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://demos.jquerymobile.com/1.4.5/css/themes/default/jquery.mobile-1.4.5.min.css">
    <script src="https://demos.jquerymobile.com/1.4.5/js/jquery.js"></script>
    <script src="https://demos.jquerymobile.com/1.4.5/js/jquery.mobile-1.4.5.min.js"></script>)';
  end;

  define tagset tagsets.mytagset;
    parent=tagsets.html4;

  define event text_group;
      start:
        ndent;
      finish:
        xdent;      
      end;

    define event text_row;
      start:
        ndent;
      finish:
        xdent;
      end;

    define event text;
      start:
        ndent;
        put value ;
      finish:
        xdent;
        put nl;
    end;
  end;
run;

 

 

 

Then I use my new tagset to start writing to the html file:

 

  ods tagsets.mytagset path="C:\dirname_here\" (url=none) file="test.html" style=styles.test;

And write some jQuery info:

 ods text= 
   '<div data-role="page">
   <div data-role="header">
   <h1>My Title</h1>
   </div><!-- /header -->
   <div role="main" class="ui-content">
   <p>Hello world</p>
   <form>
   <input id="filter-for-listview" placeholder="Type to search..." data-type="search">
   </form>
   <ul data-role="listview" data-inset="true" data-input="#filter-for-listview" data-filter="true">';

 

 

 

...and later in the loop, I call ODS to write each list item to the HTML file:

  ods text= "<li><a href='#'>&name</a></li>";

After the loop, I need to close the <ul> tag from above:

  data _null_;

    ods text= '</ul>';

  run;

...and of course at the end, close the tagset:

  ods tagsets.mytagset close;

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

Register now!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 7 replies
  • 1631 views
  • 3 likes
  • 3 in conversation