1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2018 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "data/mdd-writer.h"
22 #include <libxml/xmlwriter.h>
27 #include "data/dictionary.h"
28 #include "data/file-handle-def.h"
29 #include "data/make-file.h"
30 #include "data/short-names.h"
31 #include "data/value-labels.h"
32 #include "data/variable.h"
33 #include "libpspp/message.h"
34 #include "libpspp/misc.h"
36 #include "gl/ftoastr.h"
37 #include "gl/xalloc.h"
38 #include "gl/xmemdup0.h"
41 #define _(msgid) gettext (msgid)
42 #define N_(msgid) (msgid)
44 #define _xml(X) (CHAR_CAST (const xmlChar *, (X)))
46 /* Metadata file writer. */
49 struct file_handle *fh; /* File handle. */
50 struct fh_lock *lock; /* Mutual exclusion for file. */
51 FILE *file; /* File stream. */
52 struct replace_file *rf; /* Ticket for replacing output file. */
54 xmlTextWriter *writer;
57 /* Returns true if an I/O error has occurred on WRITER, false otherwise. */
59 mdd_write_error (const struct mdd_writer *writer)
61 return ferror (writer->file);
65 mdd_close (struct mdd_writer *w)
71 xmlFreeTextWriter (w->writer);
78 ok = !mdd_write_error (w);
79 if (fclose (w->file) == EOF)
83 msg (ME, _("An I/O error occurred writing metadata file `%s'."),
84 fh_get_file_name (w->fh));
86 if (ok ? !replace_file_commit (w->rf) : !replace_file_abort (w->rf))
99 mdd_write (struct file_handle *fh, struct dictionary *dict,
100 const char *sav_name)
102 struct mdd_writer *w = xzalloc (sizeof *w);
104 /* Open file handle as an exclusive writer. */
105 /* TRANSLATORS: this fragment will be interpolated into
106 messages in fh_lock() that identify types of files. */
107 w->lock = fh_lock (fh, FH_REF_FILE, N_("metadata file"), FH_ACC_WRITE, true);
111 /* Create the file on disk. */
112 w->rf = replace_file_start (fh, "wb", 0444, &w->file);
115 msg (ME, _("Error opening `%s' for writing as a metadata file: %s."),
116 fh_get_file_name (fh), strerror (errno));
120 w->writer = xmlNewTextWriter (xmlOutputBufferCreateFile (w->file, NULL));
123 msg (ME, _("Internal error creating xmlTextWriter."));
127 xmlTextWriterStartDocument (w->writer, NULL, "UTF-8", NULL);
129 /* <?xml-stylesheet type="text/xsl" href="mdd.xslt"?> */
130 xmlTextWriterStartPI (w->writer, _xml ("xml-stylesheet"));
131 xmlTextWriterWriteString (w->writer,
132 _xml ("type=\"text/xsl\" href=\"mdd.xslt\""));
133 xmlTextWriterEndPI (w->writer);
135 xmlTextWriterStartElement (w->writer, _xml ("xml"));
137 /* <mdm:metadata xmlns:mdm="http://www.spss.com/mr/dm/metadatamodel/Arc
138 3/2000-02-04" mdm_createversion="7.0.0.0.331"
139 mdm_lastversion="7.0.0.0.331" id="c4c181c1-0d7c-42e3-abcd-f08296d1dfdc"
140 data_version="9" data_sub_version="1" systemvariable="0"
141 dbfiltervalidation="-1"> */
142 xmlTextWriterStartElementNS (
143 w->writer, _xml ("mdm"), _xml ("xml"),
144 _xml ("http://www.spss.com/mr/dm/metadatamodel/Arc 3/2000-02-04"));
145 static const struct pair
147 const char *key, *value;
151 { "mdm_createversion", "7.0.0.0.331" },
152 { "mdm_lastversion", "7.0.0.0.331" },
153 { "id", "c4c181c1-0d7c-42e3-abcd-f08296d1dfdc" },
154 { "data_version", "9" },
155 { "data_sub_version", "1" },
156 { "systemvariable", "0" },
157 { "dbfiltervalidation", "-1" },
159 const int n_pairs = sizeof pairs / sizeof *pairs;
160 for (const struct pair *p = pairs; p < &pairs[n_pairs]; p++)
161 xmlTextWriterWriteAttribute (w->writer, _xml (p->key), _xml (p->value));
162 xmlTextWriterEndElement (w->writer);
165 xmlTextWriterStartElement (w->writer, _xml ("atoms"));
166 xmlTextWriterEndElement (w->writer);
169 xmlTextWriterStartElement (w->writer, _xml ("datasources"));
170 xmlTextWriterWriteAttribute (w->writer, _xml ("default"), _xml ("mrSavDsc"));
173 xmlTextWriterStartElement (w->writer, _xml ("connection"));
174 xmlTextWriterWriteAttribute (w->writer, _xml ("name"), _xml ("mrSavDsc"));
175 xmlTextWriterWriteAttribute (w->writer, _xml ("dblocation"),
177 xmlTextWriterWriteAttribute (w->writer,
178 _xml ("cdscname"), _xml ("mrSavDsc"));
179 xmlTextWriterWriteAttribute (w->writer, _xml ("project"), _xml ("126"));
181 size_t n_vars = dict_get_var_cnt (dict);
182 short_names_assign (dict);
183 for (size_t i = 0; i < n_vars; i++)
185 const struct variable *var = dict_get_var (dict, i);
186 xmlTextWriterStartElement (w->writer, _xml ("var"));
188 /* XXX Should convert short name to all-lowercase below. */
189 xmlTextWriterWriteAttribute (w->writer, _xml ("fullname"),
190 _xml (var_get_short_name (var, 0)));
191 xmlTextWriterWriteAttribute (w->writer, _xml ("aliasname"),
192 _xml (var_get_name (var)));
194 const struct val_labs *val_labs = var_get_value_labels (var);
195 size_t n_vls = val_labs_count (val_labs);
198 const struct val_lab **vls = val_labs_sorted (val_labs);
200 xmlTextWriterStartElement (w->writer, _xml ("nativevalues"));
201 int width = var_get_width (var);
202 for (size_t j = 0; j < n_vls; j++)
204 const struct val_lab *vl = vls[j];
205 xmlTextWriterStartElement (w->writer, _xml ("nativevalue"));
206 /* XXX Should convert to lowercase, change non-id characters to
207 _, prefix with _ if starts with non-letter */
208 xmlTextWriterWriteAttribute (w->writer, _xml ("fullname"),
209 _xml (val_lab_get_label (vl)));
211 /* XXX below would better use syntax_gen_value(). */
212 const union value *value = val_lab_get_value (vl);
215 char *s = xmemdup0 (value_str (value, width), width);
216 xmlTextWriterWriteAttribute (w->writer, _xml ("value"),
222 char s[DBL_BUFSIZE_BOUND];
224 c_dtoastr (s, sizeof s, 0, 0, value->f);
225 xmlTextWriterWriteAttribute (w->writer, _xml ("value"),
228 xmlTextWriterEndElement (w->writer);
230 xmlTextWriterEndElement (w->writer);
235 xmlTextWriterEndElement (w->writer);
238 xmlTextWriterEndElement (w->writer); /* </xml> */
240 xmlTextWriterEndDocument (w->writer);