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,"<");
22 } else if(*s=='>') {
23 xmls_add_str(rtext,">");
24 } else if(*s=='&' && s[1]!='#') {
25 xmls_add_str(rtext,"&");
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,""");
41 } else if(*s=='<') {
42 xmls_add_str(rtext,"<");
43 } else if(*s=='>') {
44 xmls_add_str(rtext,">");
45 } else if(*s=='&' && s[1]!='#') {
46 xmls_add_str(rtext,"&");
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