BookmarkSubscribeRSS Feed
Quartz | Level 8


I have been struggling with an ODS RTF problem for quite a while. The problem is that I would need to generate a RTF report with dynamic texture styles (different colors, sizes, styles etc.). The only way to do this (with my knowledge) is to use proc report/print to print out text datasets where ods escapechar is used to inject RTF tags into it. However this method has a major drawback and it is that the output is printed into tables/cells and not as "normal" text, and it makes the post processing of the RTF file really complicated.

What I would think would be the way to go is the ODS TEXT, but as far as I know there is no control statements for the ODS TEXT styles? Or is there some undocumented statements involved (if so then it could still be a problem since the code needs to work with future SAS versions too)?

Third option that I have thought, but not yet tried is to reformat the template ODS TEXT uses (if even possible?) _every_time_ before the ODS TEXT statement. This solution obviously would extremely inconvenient.

Do you guys have any solutions for this?

I am using SAS 9.4 and the reports are generated by SAS Stored Processes.

Diamond | Level 26 RW9
Diamond | Level 26

You would need to provide some more information.  RTF output from SAS is generated using the RTF tagset, you can find the code in tagsets.  Unfortunately these tagsets are not documented as far as I can tell, so its a bit of guess work to build your own tagset.  The RTF one is setup to create tables, as SAS is a dataset based program this makes sense.  There is however other options other than writing a tagset yourself:

- Directly create the RTF file yourself.  This requires understanding of the RTF syntax, but allows you total control over the output file:

data _null_;

     file "xyz.rtf";

     put "{\rtf1\ansi\ansicpg1252\uc1\deff0\deflang1033\deflangfe1033";



- Write out a text file and use a converter from txt to rtf.

- You could also try output to PDF, then PDF save as RTF.

Quartz | Level 8

Thank you for your answer! I am already using the tags to control the output, but I have to use the print method, however this "put hack" seems promising. I will try it asap.

However as I mentioned the report is generated by SAS Stored process and I wonder if it is possible to "interrupt" the rtf file (for inserting custom text) and then let SAS continue to print its tables and figures to the file again? I mean I could have a situation where I would need to print Toc title 1 title then a graph and then commentary text underneath the graph (with custom styles) and after that a new graph and so on... And if I understood correctly with this "put hack" I would need to open the current ods rtf file stream and write this put "some text" on it and then let SAS continue to do its thing into the file again?

The other methods you mentioned are not possible for me because the report must be automatically generated (on demand) to the end user without any "hassle" with the document itself.

Could you also specify what kind of information I should still provide please?

Diamond | Level 26 RW9
Diamond | Level 26

If it all needs automating, and you have knowledge of RTF, you could just post process the file to add in the information you need.  I.e.

data _null_;

     length buffer $2000;

     infile "xyz.rtf";

     file "xyz.rtf";

     input buffer $;

     if buffer="\known\rtf\string\or\tag" then do;

          put buffer;

          put "\a\new\set\of\tags\and{String data}";


     else put buffer;


However the above does require you know where and how to insert into RTF.  TBH RTF is a really poor markup to work with, I have had so much time put into parsing and understanding it.  You are aware that Word and other office products can read XML?  You could use that, i.e. ods html, ods tagsets.excelxp.

For the point about putting text under graphs, what do you mean here?  In sgplot/gtl you can have footnotes/titles embedded into the picture, the footenotes can have different styles as with any report output.  The picture is what is put into the RTF.  There are also footnotes applied to the RTF document itself.

If however you are talking more about a paragraphs of information, then in my industry this is done by a separate group.  We produce RTF outputs, then a team writes documents, embeds the RTF file we provide in, does bookmarks etc.  So this isn't an automated process - as you don't have a lot of control over the outputs.

Quartz | Level 8

Thanks again for your effort, really appreciate it.

Few things that I didn't mention (oops!) was that the report has to have a properly generated title of content (from automatically generated titles) and it must be editable via MS Word (in WYSIWYG manner).

I agree with you that the RTF is not the best horse to work with, but it satisfies all my other needs with this project and it has been previously used. But I am always open for new perspectives.

TBH I am not that familiar with XML but it sure sounds interesting, however I am a bit confused since I'm under the assumption that XML itself does "nothing". So is there a ready made list which tags can be used so that the MS Word for example can interpret them as intended? Or am I totally off with this one?

Diamond | Level 26 RW9
Diamond | Level 26

You are quite correct.  By itself, XML is noting more than a text file, with lots of extra codes much like RTF - they are both markup syntax.  The difference with XML is the additional technologies surrounding it.  Where RTF is now quite old, and M$ has also moved to XML, XML is an ongoing standard which is taking hold in most places.  You can have alongside the basic XML file, a stylesheet - like a web page style sheet, which tells to interpreter how to render the XML, colors fonts etc.  You can also have DSD, Schema files which check the integrity and validity.  You can also have XLST files which are transformation files from one version to another, or for mapping etc.  Have a look at:

Which gives some instruction on converting XML to PDF via XLST.  So you can see the technology there is well developed, and there are serious editors out there as well as it can be complex to work with, however in my opinion this is the way things will go forward away from proprietary binary formats to plain text, markedup, and self describing documents.  Have a look also at DocBook, which is a schema for documents, i.e. TOC and such like.

Back to your first point, be careful with Word.  As RTF is interpreted at read time, you might find odd things, or changes made don't work in saved document.   But yes, to automate further do look into reading the plain text rtf file, and adding things you need manually in a put statement.

One other suggestion I can give you is to create a Word file which can be used as the basis for the output.  Have SAS export the data (CSV probably), then you can have some VBA which opens CSV data and processes it into you Word file.  The benefit here being that you could export anything you want from SAS, data tables, paragraphs etc, and some format information, then in VBA read all that in and build an actual Word file.  Requires knowledge of VBA/Word, and also some kind of base constructs for export, but it is doable, although lots more work than just the RTF export.

Calcite | Level 5

Are you using Proc Report?

I have a report in which I dynamically add color to highlight data that is below a threshold.  I normally output as a PDF, but I just tried outputting it to RTF instead, and the colors were applied to the rtf file.

I have modified my code to create an example:

PROC REPORT DATA = DailyImport nowd split='/' style(report)=[frame=void rules=none] ;

  column studentid testid DateTest testgrade ;

  define studentid        / order 'StudentId'            format= 6. width=6 ;

  define testid           / display 'Test Id'            format= 4.   width=4 ;

  define DateTest         / display 'Test Date'          format=MMDDYY10. width=10 ;

  define testgrade        / display 'Grade'              format=abc.  width=6 CENTER ;

  define failure          / noprint ;

  compute failure ;

  if testgrade <= 2 then

  CALL define (_row_, "style", "style=") ;

  else if testgrade = 3 then

  CALL define (_row_, "style", "style=") ;  *orange ;

  endcomp ;

  compute after studentid / style=[font_size=1pt background=cxf0f0f0] ;

  *put a line of gray shading between students ;

  line ' ' ;

  endcomp ;

  title1 "Student Grades" ;

  title2 "Daily Load: &sysdate" ;

run ;

(p.s. I hope I didn't introduce any syntax errors in this code... no guarantees!)


Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.


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
  • 6 replies
  • 3 in conversation