1 /*
2  *  TurboXSL XML+XSLT processing library
3  *  XML nodeset to text convertor,
4  *  file output.
5  *
6  *  (c) Egor Voznessenski, voznyak@mail.ru
7  *
8  *  $Id$
9  *
10 **/
11 
12 #include <stdio.h>
13 
14 #include "ltr_xsl.h"
15 #include "xsl_elements.h"
16 
add_quoted_str(XMLSTRING rtext,char * s)17 void add_quoted_str(XMLSTRING rtext, char *s)
18 {
19   while(*s) {
20     if(*s=='<') {
21       xmls_add_str(rtext,"&lt;");
22     } else if(*s=='>') {
23       xmls_add_str(rtext,"&gt;");
24     } else if(*s=='&' && s[1]!='#') {
25       xmls_add_str(rtext,"&amp;");
26     } else {
27       xmls_add_char(rtext,*s);
28     }
29     ++s;
30   }
31 }
32 
add_quoted_attribute_value(XMLSTRING rtext,XMLSTRING value)33 void add_quoted_attribute_value(XMLSTRING rtext, XMLSTRING value)
34 {
35   if(value==NULL) return;
36 
37   char *s = value->s;
38   while(*s) {
39     if(*s=='"') {
40       xmls_add_str(rtext,"&quot;");
41     } else if(*s=='<') {
42       xmls_add_str(rtext,"&lt;");
43     } else if(*s=='>') {
44       xmls_add_str(rtext,"&gt;");
45     } else if(*s=='&' && s[1]!='#') {
46       xmls_add_str(rtext,"&amp;");
47     } else {
48       xmls_add_char(rtext,*s);
49     }
50     ++s;
51   }
52 }
53 
is_html_empty_tag(XMLSTRING name)54 static int is_html_empty_tag(XMLSTRING name)
55 {
56   if(xmls_equals(name, xsl_s_img)) return 1;
57   if(xmls_equals(name, xsl_s_meta)) return 1;
58   if(xmls_equals(name, xsl_s_hr)) return 1;
59   if(xmls_equals(name, xsl_s_br)) return 1;
60   if(xmls_equals(name, xsl_s_link)) return 1;
61   if(xmls_equals(name, xsl_s_input)) return 1;
62 
63   return 0;
64 }
65 
output_node_rec(XMLNODE * node,XMLSTRING rtext,TRANSFORM_CONTEXT * ctx)66 void output_node_rec(XMLNODE *node, XMLSTRING rtext, TRANSFORM_CONTEXT *ctx)
67 {
68   XMLNODE *attr;
69 
70   while(node) {
71     switch(node->type) {
72       case ELEMENT_NODE:
73         xmls_add_char(rtext,'<');
74         xmls_append(rtext, node->name);
75         for(attr=node->attributes;attr;attr=attr->next) {
76           xmls_add_char(rtext,' ');
77           xmls_append(rtext, attr->name);
78           xmls_add_str(rtext, "=\"");
79           add_quoted_attribute_value(rtext, attr->content);
80           xmls_add_char(rtext,'"');
81         }
82         if(ctx->outmode==MODE_HTML && is_html_empty_tag(node->name)) {
83           xmls_add_str(rtext,">");
84         } else {
85           if(node->children) {
86             if(ctx->rawout || (ctx->outmode==MODE_HTML && xmls_equals(node->name,xsl_s_script))) {
87               ++ctx->rawout;
88             }
89             xmls_add_char(rtext,'>');
90             output_node_rec(node->children, rtext, ctx);
91             if(ctx->rawout){
92               --ctx->rawout;
93             }
94             xmls_add_str(rtext, "</");
95             xmls_append(rtext, node->name);
96             xmls_add_char(rtext,'>');
97           } else {
98             if(ctx->outmode==MODE_XML) {
99               xmls_add_str(rtext,"/>");
100             } else {
101               xmls_add_str(rtext, "></");
102               xmls_append(rtext, node->name);
103               xmls_add_char(rtext,'>');
104             }
105           }
106         }
107         break;
108       case COMMENT_NODE:
109         xmls_add_str(rtext,"<!--");
110         if(node->content) {
111           xmls_append(rtext, node->content);
112         }
113         xmls_add_str(rtext,"-->");
114         break;
115       case PI_NODE:
116         xmls_add_str(rtext,"<?");
117         xmls_append(rtext, node->name);
118         if(node->content) {
119           xmls_add_char(rtext,' ');
120           xmls_append(rtext, node->content);
121         }
122         xmls_add_char(rtext,'>');
123         break;
124       case TEXT_NODE:
125         if(node->flags & XML_FLAG_CDATA)
126           xmls_add_str(rtext, "<![CDATA[");
127         if((node->flags & XML_FLAG_NOESCAPE)||(ctx->rawout)) {
128           xmls_append(rtext, node->content);
129         } else {
130           if(node->content != NULL) add_quoted_str(rtext, node->content->s);
131         }
132         if(node->flags & XML_FLAG_CDATA)
133           xmls_add_str(rtext, "]]>");
134         break;
135       default:
136         output_node_rec(node->children, rtext, ctx);
137     }
138     node = node->next;
139   }
140 }
141 
XMLOutput(TRANSFORM_CONTEXT * ctx,XMLNODE * tree)142 char *XMLOutput(TRANSFORM_CONTEXT *ctx, XMLNODE *tree)
143 {
144   XMLSTRING rtext = xmls_new(10000);
145   XMLNODE *t;
146   if(ctx->outmode==MODE_XML) {
147     if(!(ctx->flags & XSL_FLAG_OMIT_DESC)) {
148       xmls_add_str(rtext, "<?xml version=\"1.0\"");
149       if(ctx->encoding)
150         xmls_add_str(rtext, " encoding=\"UTF-8\"");
151       if(ctx->flags & XSL_FLAG_STANDALONE)
152         xmls_add_str(rtext, " standalone=\"yes\"");
153       xmls_add_str(rtext, "?>\n");
154     }
155   }
156 
157   if(ctx->doctype_public && ctx->doctype_system) {
158     t = find_first_node(tree);
159     if (t != NULL)
160     {
161       xmls_add_str(rtext, "<!DOCTYPE html PUBLIC \"");
162       xmls_add_str(rtext, ctx->doctype_public ? ctx->doctype_public->s : "-//W3C//DTD XHTML+RDFa 1.0//EN");
163       xmls_add_str(rtext, "\" \"");
164       xmls_add_str(rtext, ctx->doctype_system ? ctx->doctype_system->s : "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd");
165       xmls_add_str(rtext, "\">\n");
166     }
167     else
168     {
169       error("XMLOutput:: first node not found");
170     }
171   }
172   if(tree)
173     output_node_rec(tree,rtext,ctx);
174   return xmls_detach(rtext);
175 }
176 
XMLOutputFile(TRANSFORM_CONTEXT * ctx,XMLNODE * tree,char * filename)177 void XMLOutputFile(TRANSFORM_CONTEXT *ctx, XMLNODE *tree, char *filename)
178 {
179   FILE *f = fopen(filename,"w");
180   if(!f) {
181     error("XMLOutputFile:: failed to create output file %s",filename);
182     return;
183   }
184   char *result = XMLOutput(ctx, tree);
185   if(result)
186   {
187     fputs(result, f);
188     fputs("\n",f);
189   }
190   fclose(f);
191 }
192