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

akonadi

  • sources
  • kde-4.12
  • kdepimlibs
  • akonadi
  • xml
xmldocument.cpp
1 /*
2  Copyright (c) 2009 Volker Krause <vkrause@kde.org>
3 
4  This library is free software; you can redistribute it and/or modify it
5  under the terms of the GNU Library General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or (at your
7  option) any later version.
8 
9  This library is distributed in the hope that it will be useful, but WITHOUT
10  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
12  License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to the
16  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  02110-1301, USA.
18 */
19 
20 #include "xmldocument.h"
21 #include "format_p.h"
22 #include "xmlreader.h"
23 
24 #include <KDebug>
25 #include <KGlobal>
26 #include <KLocale>
27 #include <KStandardDirs>
28 
29 #include <qdom.h>
30 #include <qfile.h>
31 
32 #ifdef HAVE_LIBXML2
33 #include <libxml/parser.h>
34 #include <libxml/xmlIO.h>
35 #include <libxml/xmlschemas.h>
36 #endif
37 
38 static const KCatalogLoader loader( QLatin1String( "libakonadi-xml") );
39 
40 using namespace Akonadi;
41 
42 // helper class for dealing with libxml resource management
43 template <typename T, void FreeFunc(T)> class XmlPtr
44 {
45  public:
46  XmlPtr( const T &t ) : p( t ) {}
47 
48  ~XmlPtr()
49  {
50  FreeFunc( p );
51  }
52 
53  operator T() const
54  {
55  return p;
56  }
57 
58  operator bool() const
59  {
60  return p != 0;
61  }
62 
63  private:
64  T p;
65 };
66 
67 static QDomElement findElementByRidHelper( const QDomElement &elem, const QString &rid, const QString &elemName )
68 {
69  if ( elem.isNull() )
70  return QDomElement();
71  if ( elem.tagName() == elemName && elem.attribute( Format::Attr::remoteId() ) == rid )
72  return elem;
73  const QDomNodeList children = elem.childNodes();
74  for ( int i = 0; i < children.count(); ++i ) {
75  const QDomElement child = children.at( i ).toElement();
76  if ( child.isNull() )
77  continue;
78  const QDomElement rv = findElementByRidHelper( child, rid, elemName );
79  if ( !rv.isNull() )
80  return rv;
81  }
82  return QDomElement();
83 }
84 
85 namespace Akonadi {
86 
87 class XmlDocumentPrivate
88 {
89  public:
90  XmlDocumentPrivate() :
91  valid( false )
92  {
93  lastError = i18n( "No data loaded." );
94  }
95 
96  QDomElement findElementByRid( const QString &rid, const QString &elemName ) const
97  {
98  return findElementByRidHelper( document.documentElement(), rid, elemName );
99  }
100 
101  QDomDocument document;
102  QString lastError;
103  bool valid;
104 };
105 
106 }
107 
108 XmlDocument::XmlDocument() :
109  d( new XmlDocumentPrivate )
110 {
111  const QDomElement rootElem = d->document.createElement( Format::Tag::root() );
112  d->document.appendChild( rootElem );
113 }
114 
115 XmlDocument::XmlDocument(const QString& fileName) :
116  d( new XmlDocumentPrivate )
117 {
118  loadFile( fileName );
119 }
120 
121 XmlDocument::~XmlDocument()
122 {
123  delete d;
124 }
125 
126 bool Akonadi::XmlDocument::loadFile(const QString& fileName)
127 {
128  d->valid = false;
129  d->document = QDomDocument();
130 
131  if ( fileName.isEmpty() ) {
132  d->lastError = i18n( "No filename specified" );
133  return false;
134  }
135 
136  QFile file( fileName );
137  QByteArray data;
138  if ( file.exists() ) {
139  if ( !file.open( QIODevice::ReadOnly ) ) {
140  d->lastError = i18n( "Unable to open data file '%1'.", fileName );
141  return false;
142  }
143  data = file.readAll();
144  } else {
145  d->lastError = i18n( "File %1 does not exist.", fileName );
146  return false;
147  }
148 
149 #ifdef HAVE_LIBXML2
150  // schema validation
151  XmlPtr<xmlDocPtr, xmlFreeDoc> sourceDoc( xmlParseMemory( data.constData(), data.length() ) );
152  if ( !sourceDoc ) {
153  d->lastError = i18n( "Unable to parse data file '%1'.", fileName );
154  return false;
155  }
156 
157  const QString &schemaFileName = KGlobal::dirs()->findResource( "data", QLatin1String("akonadi/akonadi-xml.xsd") );
158  XmlPtr<xmlDocPtr, xmlFreeDoc> schemaDoc( xmlReadFile( schemaFileName.toLocal8Bit(), 0, XML_PARSE_NONET ) );
159  if ( !schemaDoc ) {
160  d->lastError = i18n( "Schema definition could not be loaded and parsed." );
161  return false;
162  }
163  XmlPtr<xmlSchemaParserCtxtPtr, xmlSchemaFreeParserCtxt> parserContext( xmlSchemaNewDocParserCtxt( schemaDoc ) );
164  if ( !parserContext ) {
165  d->lastError = i18n( "Unable to create schema parser context." );
166  return false;
167  }
168  XmlPtr<xmlSchemaPtr, xmlSchemaFree> schema( xmlSchemaParse( parserContext ) );
169  if ( !schema ) {
170  d->lastError = i18n( "Unable to create schema." );
171  return false;
172  }
173  XmlPtr<xmlSchemaValidCtxtPtr, xmlSchemaFreeValidCtxt> validationContext( xmlSchemaNewValidCtxt( schema ) );
174  if ( !validationContext ) {
175  d->lastError = i18n( "Unable to create schema validation context." );
176  return false;
177  }
178 
179  if ( xmlSchemaValidateDoc( validationContext, sourceDoc ) != 0 ) {
180  d->lastError = i18n( "Invalid file format." );
181  return false;
182  }
183 #endif
184 
185  // DOM loading
186  QString errMsg;
187  if ( !d->document.setContent( data, true, &errMsg ) ) {
188  d->lastError = i18n( "Unable to parse data file: %1", errMsg );
189  return false;
190  }
191 
192  d->valid = true;
193  d->lastError.clear();
194  return true;
195 }
196 
197 bool XmlDocument::writeToFile(const QString& fileName) const
198 {
199  QFile f( fileName );
200  if ( !f.open( QFile::WriteOnly ) ) {
201  d->lastError = f.errorString();
202  return false;
203  }
204 
205  f.write( d->document.toByteArray( 2 ) );
206 
207  d->lastError.clear();
208  return true;
209 }
210 
211 bool XmlDocument::isValid() const
212 {
213  return d->valid;
214 }
215 
216 QString XmlDocument::lastError() const
217 {
218  return d->lastError;
219 }
220 
221 QDomDocument& XmlDocument::document() const
222 {
223  return d->document;
224 }
225 
226 QDomElement XmlDocument::collectionElementByRemoteId(const QString& rid) const
227 {
228  return d->findElementByRid( rid, Format::Tag::collection() );
229 }
230 
231 QDomElement XmlDocument::collectionElement( const Collection &collection ) const
232 {
233  if ( collection == Collection::root() )
234  return d->document.documentElement();
235  if ( collection.remoteId().isEmpty() )
236  return QDomElement();
237  if ( collection.parentCollection().remoteId().isEmpty() && collection.parentCollection() != Collection::root() )
238  return d->findElementByRid( collection.remoteId(), Format::Tag::collection() );
239  QDomElement parent = collectionElement( collection.parentCollection() );
240  if ( parent.isNull() )
241  return QDomElement();
242  const QDomNodeList children = parent.childNodes();
243  for ( int i = 0; i < children.count(); ++i ) {
244  const QDomElement child = children.at( i ).toElement();
245  if ( child.isNull() )
246  continue;
247  if ( child.tagName() == Format::Tag::collection() && child.attribute( Format::Attr::remoteId() ) == collection.remoteId() )
248  return child;
249  }
250  return QDomElement();
251 }
252 
253 QDomElement XmlDocument::itemElementByRemoteId(const QString& rid) const
254 {
255  return d->findElementByRid( rid, Format::Tag::item() );
256 }
257 
258 Collection XmlDocument::collectionByRemoteId(const QString& rid) const
259 {
260  const QDomElement elem = collectionElementByRemoteId( rid );
261  return XmlReader::elementToCollection( elem );
262 }
263 
264 Item XmlDocument::itemByRemoteId(const QString& rid, bool includePayload) const
265 {
266  return XmlReader::elementToItem( itemElementByRemoteId( rid ), includePayload );
267 }
268 
269 Collection::List XmlDocument::collections() const
270 {
271  return XmlReader::readCollections( d->document.documentElement() );
272 }
273 
274 Collection::List XmlDocument::childCollections(const QString& parentCollectionRid) const
275 {
276  Collection c;
277  c.setRemoteId( parentCollectionRid );
278  return childCollections( c );
279 }
280 
281 Collection::List XmlDocument::childCollections( const Collection &parentCollection ) const
282 {
283  QDomElement parentElem = collectionElement( parentCollection );
284 
285  if ( parentElem.isNull() ) {
286  d->lastError = QLatin1String( "Parent node not found." );
287  return Collection::List();
288  }
289 
290  Collection::List rv;
291  const QDomNodeList children = parentElem.childNodes();
292  for ( int i = 0; i < children.count(); ++i ) {
293  const QDomElement childElem = children.at( i ).toElement();
294  if ( childElem.isNull() || childElem.tagName() != Format::Tag::collection() )
295  continue;
296  Collection c = XmlReader::elementToCollection( childElem );
297  c.setParentCollection( parentCollection );
298  rv.append( c );
299  }
300 
301  return rv;
302 }
303 
304 
305 Item::List XmlDocument::items(const Akonadi::Collection& collection, bool includePayload) const
306 {
307  const QDomElement colElem = collectionElement( collection );
308  if ( colElem.isNull() ) {
309  d->lastError = i18n( "Unable to find collection %1", collection.name() );
310  return Item::List();
311  } else {
312  d->lastError.clear();
313  }
314 
315  Item::List items;
316  const QDomNodeList children = colElem.childNodes();
317  for ( int i = 0; i < children.count(); ++i ) {
318  const QDomElement itemElem = children.at( i ).toElement();
319  if ( itemElem.isNull() || itemElem.tagName() != Format::Tag::item() )
320  continue;
321  items += XmlReader::elementToItem( itemElem, includePayload );
322  }
323 
324  return items;
325 }
Akonadi::XmlReader::elementToItem
AKONADI_XML_EXPORT Item elementToItem(const QDomElement &elem, bool includePayload=true)
Converts an item element.
Definition: xmlreader.cpp:88
Akonadi::XmlDocument::isValid
bool isValid() const
Returns true if the document could be parsed successfully.
Definition: xmldocument.cpp:211
Akonadi::Collection::name
QString name() const
Returns the i18n'ed name of the collection.
Definition: collection.cpp:81
Akonadi::XmlDocument::collectionElement
QDomElement collectionElement(const Collection &collection) const
Returns the DOM element representing collection.
Definition: xmldocument.cpp:231
Akonadi::XmlReader::readCollections
AKONADI_XML_EXPORT Collection::List readCollections(const QDomElement &elem)
Reads recursively all collections starting from the given DOM element.
Definition: xmlreader.cpp:71
Akonadi::XmlDocument::document
QDomDocument & document() const
Returns the DOM document for this XML document.
Definition: xmldocument.cpp:221
Akonadi::XmlDocument::writeToFile
bool writeToFile(const QString &fileName) const
Writes the current document into the given file.
Definition: xmldocument.cpp:197
Akonadi::XmlDocument::loadFile
bool loadFile(const QString &fileName)
Parses the given XML file and validates it.
Definition: xmldocument.cpp:126
Akonadi::Collection
Represents a collection of PIM items.
Definition: collection.h:75
Akonadi::XmlReader::elementToCollection
AKONADI_XML_EXPORT Collection elementToCollection(const QDomElement &elem)
Converts a collection element.
Definition: xmlreader.cpp:53
Akonadi::Entity::setRemoteId
void setRemoteId(const QString &id)
Sets the remote id of the entity.
Definition: entity.cpp:77
Akonadi::XmlDocument::XmlDocument
XmlDocument()
Creates an empty document.
Definition: xmldocument.cpp:108
Akonadi::Entity::setParentCollection
void setParentCollection(const Collection &parent)
Set the parent collection of this object.
Definition: entity.cpp:195
Akonadi::XmlDocument::itemElementByRemoteId
QDomElement itemElementByRemoteId(const QString &rid) const
Returns the DOM element representing the item with the given remote id.
Definition: xmldocument.cpp:253
Akonadi::Entity::parentCollection
Collection parentCollection() const
Returns the parent collection of this object.
Definition: entity.cpp:186
Akonadi::Entity::remoteId
QString remoteId() const
Returns the remote id of the entity.
Definition: entity.cpp:82
Akonadi::XmlDocument::lastError
QString lastError() const
Returns the last error occurred during file loading/parsing.
Definition: xmldocument.cpp:216
Akonadi::XmlDocument::collectionElementByRemoteId
QDomElement collectionElementByRemoteId(const QString &rid) const
Returns the DOM element representing the collection with the given remote id.
Definition: xmldocument.cpp:226
Akonadi::Collection::root
static Collection root()
Returns the root collection.
Definition: collection.cpp:192
Akonadi::XmlDocument::collectionByRemoteId
Collection collectionByRemoteId(const QString &rid) const
Returns the collection with the given remote id.
Definition: xmldocument.cpp:258
Akonadi::XmlDocument::collections
Collection::List collections() const
Returns the collections defined in this document.
Definition: xmldocument.cpp:269
Akonadi::XmlDocument::items
Item::List items(const Collection &collection, bool includePayload=true) const
Returns the items in the given collection.
Definition: xmldocument.cpp:305
Akonadi::XmlDocument::itemByRemoteId
Item itemByRemoteId(const QString &rid, bool includePayload=true) const
Returns the item with the given remote id.
Definition: xmldocument.cpp:264
Akonadi::Collection::List
QList< Collection > List
Describes a list of collections.
Definition: collection.h:81
Akonadi::XmlDocument::childCollections
Collection::List childCollections(const QString &parentCollectionRid) const
Returns immediate child collections of the specified parent collection.
Definition: xmldocument.cpp:274
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 23:00:28 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

akonadi

Skip menu "akonadi"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Modules
  • Related Pages

kdepimlibs API Reference

Skip menu "kdepimlibs API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kldap
  • kmbox
  • kmime
  • kpimidentities
  • kpimtextedit
  • kresources
  • ktnef
  • kxmlrpcclient
  • microblog

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