• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

KDocTools

  • sources
  • kde-4.14
  • kdelibs
  • kdoctools
xslt.cpp
Go to the documentation of this file.
1 #include "xslt.h"
2 
3 #include <libxslt/xsltconfig.h>
4 #include <libxslt/xsltInternals.h>
5 #include <libxslt/transform.h>
6 #include <libxslt/xsltutils.h>
7 #include <libxml/xmlIO.h>
8 #include <libxml/parserInternals.h>
9 #include <libxml/catalog.h>
10 #include <QtCore/QDate>
11 #include <QtCore/QDir>
12 #include <QtCore/QRegExp>
13 #include <assert.h>
14 #include <QtCore/QTextCodec>
15 #include <stdlib.h>
16 #include <stdarg.h>
17 
18 #ifdef Q_OS_WIN
19 #include <config-kdoctools.h>
20 #include <QtCore/QCoreApplication>
21 #include <QtCore/QDebug>
22 #include <QtCore/QHash>
23 #endif
24 
25 #if !defined( SIMPLE_XSLT )
26 extern HelpProtocol *slave;
27 #define INFO( x ) if (slave) slave->infoMessage(x);
28 #else
29 #define INFO( x )
30 #endif
31 
32 int writeToQString(void * context, const char * buffer, int len)
33 {
34  QString *t = (QString*)context;
35  *t += QString::fromUtf8(buffer, len);
36  return len;
37 }
38 
39 int closeQString(void * context) {
40  QString *t = (QString*)context;
41  *t += '\n';
42  return 0;
43 }
44 
45 #if defined (SIMPLE_XSLT) && defined(Q_WS_WIN)
46 
47 #define MAX_PATHS 64
48 xmlExternalEntityLoader defaultEntityLoader = NULL;
49 static xmlChar *paths[MAX_PATHS + 1];
50 static int nbpaths = 0;
51 static QHash<QString,QString> replaceURLList;
52 
53 /*
54 * Entity loading control and customization.
55 * taken from xsltproc.c
56 */
57 static xmlParserInputPtr xsltprocExternalEntityLoader(const char *_URL, const char *ID,xmlParserCtxtPtr ctxt)
58 {
59  xmlParserInputPtr ret;
60  warningSAXFunc warning = NULL;
61 
62  // use local available dtd versions instead of fetching it everytime from the internet
63  QString url = QLatin1String(_URL);
64  QHash<QString, QString>::const_iterator i;
65  for(i = replaceURLList.constBegin(); i != replaceURLList.constEnd(); i++)
66  {
67  if (url.startsWith(i.key()))
68  {
69  url.replace(i.key(),i.value());
70  qDebug() << "converted" << _URL << "to" << url;
71  }
72  }
73  char URL[1024];
74  strcpy(URL,url.toLatin1().constData());
75 
76  const char *lastsegment = URL;
77  const char *iter = URL;
78 
79  if (nbpaths > 0) {
80  while (*iter != 0) {
81  if (*iter == '/')
82  lastsegment = iter + 1;
83  iter++;
84  }
85  }
86 
87  if ((ctxt != NULL) && (ctxt->sax != NULL)) {
88  warning = ctxt->sax->warning;
89  ctxt->sax->warning = NULL;
90  }
91 
92  if (defaultEntityLoader != NULL) {
93  ret = defaultEntityLoader(URL, ID, ctxt);
94  if (ret != NULL) {
95  if (warning != NULL)
96  ctxt->sax->warning = warning;
97  qDebug() << "Loaded URL=\"" << URL << "\" ID=\"" << ID << "\"";
98  return(ret);
99  }
100  }
101  for (int i = 0;i < nbpaths;i++) {
102  xmlChar *newURL;
103 
104  newURL = xmlStrdup((const xmlChar *) paths[i]);
105  newURL = xmlStrcat(newURL, (const xmlChar *) "/");
106  newURL = xmlStrcat(newURL, (const xmlChar *) lastsegment);
107  if (newURL != NULL) {
108  ret = defaultEntityLoader((const char *)newURL, ID, ctxt);
109  if (ret != NULL) {
110  if (warning != NULL)
111  ctxt->sax->warning = warning;
112  qDebug() << "Loaded URL=\"" << newURL << "\" ID=\"" << ID << "\"";
113  xmlFree(newURL);
114  return(ret);
115  }
116  xmlFree(newURL);
117  }
118  }
119  if (warning != NULL) {
120  ctxt->sax->warning = warning;
121  if (URL != NULL)
122  warning(ctxt, "failed to load external entity \"%s\"\n", URL);
123  else if (ID != NULL)
124  warning(ctxt, "failed to load external entity \"%s\"\n", ID);
125  }
126  return(NULL);
127 }
128 #endif
129 
130 QString transform( const QString &pat, const QString& tss,
131  const QVector<const char *> &params )
132 {
133  QString parsed;
134 
135  INFO(i18n("Parsing stylesheet"));
136 #if defined (SIMPLE_XSLT) && defined(Q_WS_WIN)
137  // prepare use of local available dtd versions instead of fetching everytime from the internet
138  // this approach is url based
139  if (!defaultEntityLoader) {
140  defaultEntityLoader = xmlGetExternalEntityLoader();
141  xmlSetExternalEntityLoader(xsltprocExternalEntityLoader);
142 
143  replaceURLList[QLatin1String("http://www.oasis-open.org/docbook/xml/4.2")] = QString("file:///%1").arg(DOCBOOK_XML_CURRDTD);
144  }
145 #endif
146 
147  xsltStylesheetPtr style_sheet =
148  xsltParseStylesheetFile((const xmlChar *)QFile::encodeName(tss).constData());
149 
150  if ( !style_sheet ) {
151  return parsed;
152  }
153  if (style_sheet->indent == 1)
154  xmlIndentTreeOutput = 1;
155  else
156  xmlIndentTreeOutput = 0;
157 
158  INFO(i18n("Parsing document"));
159 
160  xmlParserCtxtPtr pctxt;
161 
162  pctxt = xmlNewParserCtxt();
163  if ( pctxt == NULL ) {
164  return parsed;
165  }
166 
167  xmlDocPtr doc = xmlCtxtReadFile(pctxt, QFile::encodeName(pat), NULL,
168  XML_PARSE_NOENT|XML_PARSE_DTDLOAD|XML_PARSE_NONET);
169  /* Check both the returned doc (for parsing errors) and the context
170  (for validation errors) */
171  if (doc == NULL) {
172  return parsed;
173  } else {
174  if (pctxt->valid == 0) {
175  xmlFreeDoc(doc);
176  return parsed;
177  }
178  }
179 
180  xsltTransformContextPtr ctxt;
181 
182  ctxt = xsltNewTransformContext(style_sheet, doc);
183  if (ctxt == NULL)
184  return parsed;
185 
186  INFO(i18n("Applying stylesheet"));
187  QVector<const char *> p = params;
188  p.append( NULL );
189  xmlDocPtr res = xsltApplyStylesheet(style_sheet, doc, const_cast<const char **>(&p[0]));
190  xmlFreeDoc(doc);
191  if (res != NULL) {
192  xmlOutputBufferPtr outp = xmlOutputBufferCreateIO(writeToQString, (xmlOutputCloseCallback)closeQString, &parsed, 0);
193  outp->written = 0;
194  INFO(i18n("Writing document"));
195  xsltSaveResultTo ( outp, res, style_sheet );
196  xmlOutputBufferFlush(outp);
197  xmlFreeDoc(res);
198  }
199  xsltFreeStylesheet(style_sheet);
200 
201  if (parsed.isEmpty())
202  parsed = ' '; // avoid error message
203  return parsed;
204 }
205 
206 /*
207 xmlParserInputPtr meinExternalEntityLoader(const char *URL, const char *ID,
208  xmlParserCtxtPtr ctxt) {
209  xmlParserInputPtr ret = NULL;
210 
211  // fprintf(stderr, "loading %s %s %s\n", URL, ID, ctxt->directory);
212 
213  if (URL == NULL) {
214  if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
215  ctxt->sax->warning(ctxt,
216  "failed to load external entity \"%s\"\n", ID);
217  return(NULL);
218  }
219  if (!qstrcmp(ID, "-//OASIS//DTD DocBook XML V4.1.2//EN"))
220  URL = "docbook/xml-dtd-4.1.2/docbookx.dtd";
221  if (!qstrcmp(ID, "-//OASIS//DTD XML DocBook V4.1.2//EN"))
222  URL = "docbook/xml-dtd-4.1.2/docbookx.dtd";
223 
224  QString file;
225  if (KStandardDirs::exists( QDir::currentPath() + "/" + URL ) )
226  file = QDir::currentPath() + "/" + URL;
227  else
228  file = locate("dtd", URL);
229 
230  ret = xmlNewInputFromFile(ctxt, file.toLatin1().constData());
231  if (ret == NULL) {
232  if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
233  ctxt->sax->warning(ctxt,
234 
235  "failed to load external entity \"%s\"\n", URL);
236  }
237  return(ret);
238 }
239 */
240 
241 QString splitOut(const QString &parsed, int index)
242 {
243  int start_index = index + 1;
244  while (parsed.at(start_index - 1) != '>') start_index++;
245 
246  int inside = 0;
247 
248  QString filedata;
249 
250  while (true) {
251  int endindex = parsed.indexOf("</FILENAME>", index);
252  int startindex = parsed.indexOf("<FILENAME ", index) + 1;
253 
254 // kDebug() << "FILENAME " << startindex << " " << endindex << " " << inside << " " << parsed.mid(startindex + 18, 15)<< " " << parsed.length();
255 
256  if (startindex > 0) {
257  if (startindex < endindex) {
258  // kDebug() << "finding another";
259  index = startindex + 8;
260  inside++;
261  } else {
262  index = endindex + 8;
263  inside--;
264  }
265  } else {
266  inside--;
267  index = endindex + 1;
268  }
269 
270  if (inside == 0) {
271  filedata = parsed.mid(start_index, endindex - start_index);
272  break;
273  }
274 
275  }
276 
277  index = filedata.indexOf("<FILENAME ");
278 
279  if (index > 0) {
280  int endindex = filedata.lastIndexOf("</FILENAME>");
281  while (filedata.at(endindex) != '>') endindex++;
282  endindex++;
283  filedata = filedata.left(index) + filedata.mid(endindex);
284  }
285 
286  // filedata.replace(QRegExp(">"), "\n>");
287  return filedata;
288 }
289 
290 QByteArray fromUnicode( const QString &data )
291 {
292 #ifdef Q_WS_WIN
293  return data.toUtf8();
294 #else
295  QTextCodec *locale = QTextCodec::codecForLocale();
296  QByteArray result;
297  char buffer[30000];
298  uint buffer_len = 0;
299  uint len = 0;
300  int offset = 0;
301  const int part_len = 5000;
302 
303  QString part;
304 
305  while ( offset < data.length() )
306  {
307  part = data.mid( offset, part_len );
308  QByteArray test = locale->fromUnicode( part );
309  if ( locale->toUnicode( test ) == part ) {
310  result += test;
311  offset += part_len;
312  continue;
313  }
314  len = part.length();
315  buffer_len = 0;
316  for ( uint i = 0; i < len; i++ ) {
317  QByteArray test = locale->fromUnicode( part.mid( i, 1 ) );
318  if ( locale->toUnicode( test ) == part.mid( i, 1 ) ) {
319  if (buffer_len + test.length() + 1 > sizeof(buffer))
320  break;
321  strcpy( buffer + buffer_len, test.data() );
322  buffer_len += test.length();
323  } else {
324  QString res;
325  res.sprintf( "&#%d;", part.at( i ).unicode() );
326  test = locale->fromUnicode( res );
327  if (buffer_len + test.length() + 1 > sizeof(buffer))
328  break;
329  strcpy( buffer + buffer_len, test.data() );
330  buffer_len += test.length();
331  }
332  }
333  result += QByteArray( buffer, buffer_len + 1);
334  offset += part_len;
335  }
336  return result;
337 #endif
338 }
339 
340 void replaceCharsetHeader( QString &output )
341 {
342  QString name;
343 #ifdef Q_WS_WIN
344  name = "utf-8";
345  // may be required for all xml output
346  if (output.contains("<table-of-contents>"))
347  output.replace( QString( "<?xml version=\"1.0\"?>" ),
348  QString( "<?xml version=\"1.0\" encoding=\"%1\"?>").arg( name ) );
349 #else
350  name = QTextCodec::codecForLocale()->name();
351  name.replace( QString( "ISO " ), "iso-" );
352  output.replace( QString( "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">" ),
353  QString( "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%1\">" ).arg( name ) );
354 #endif
355 }
transform
QString transform(const QString &pat, const QString &tss, const QVector< const char * > &params)
Definition: xslt.cpp:130
i18n
QString i18n(const char *text)
QTextCodec::fromUnicode
QByteArray fromUnicode(const QString &str) const
QString::indexOf
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
HelpProtocol
Definition: kio_help.h:36
replaceCharsetHeader
void replaceCharsetHeader(QString &output)
Definition: xslt.cpp:340
QHash::key
const Key key(const T &value) const
QTextCodec::name
virtual QByteArray name() const =0
QVector::append
void append(const T &value)
QByteArray
name
const char * name(StandardAction id)
QByteArray::length
int length() const
QTextCodec::codecForLocale
QTextCodec * codecForLocale()
QString::lastIndexOf
int lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
QString::fromUtf8
QString fromUtf8(const char *str, int size)
QHash::constEnd
const_iterator constEnd() const
splitOut
QString splitOut(const QString &parsed, int index)
Definition: xslt.cpp:241
QHash< QString, QString >
test
KGuiItem test()
xslt.h
QString::isEmpty
bool isEmpty() const
QByteArray::constData
const char * constData() const
QString::startsWith
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
QString
QChar::unicode
ushort unicode() const
QTextCodec
fromUnicode
QByteArray fromUnicode(const QString &data)
Definition: xslt.cpp:290
QHash::value
const T value(const Key &key) const
QString::contains
bool contains(QChar ch, Qt::CaseSensitivity cs) const
locale
KLocale * locale()
QString::replace
QString & replace(int position, int n, QChar after)
QHash::constBegin
const_iterator constBegin() const
QString::toLatin1
QByteArray toLatin1() const
QString::mid
QString mid(int position, int n) const
QVector
QLatin1String
INFO
#define INFO(x)
Definition: xslt.cpp:27
QString::sprintf
QString & sprintf(const char *cformat,...)
QString::at
const QChar at(int position) const
writeToQString
int writeToQString(void *context, const char *buffer, int len)
Definition: xslt.cpp:32
QString::length
int length() const
QByteArray::data
char * data()
QString::left
QString left(int n) const
slave
HelpProtocol * slave
Definition: kio_help.cpp:174
QString::arg
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
closeQString
int closeQString(void *context)
Definition: xslt.cpp:39
QTextCodec::toUnicode
QString toUnicode(const QByteArray &a) const
QFile::encodeName
QByteArray encodeName(const QString &fileName)
QString::toUtf8
QByteArray toUtf8() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:26:01 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDocTools

Skip menu "KDocTools"
  • Main Page
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal