Syndication

elementwrapper.cpp
1/*
2 This file is part of the syndication library
3 SPDX-FileCopyrightText: 2006 Frank Osterfeld <osterfeld@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "elementwrapper.h"
9#include "constants.h"
10
11#include <QUrl>
12
13#include <QDomDocument>
14#include <QDomElement>
15#include <QIODevice>
16#include <QStringList>
17#include <QTextStream>
18
19namespace Syndication
20{
21class SYNDICATION_NO_EXPORT ElementWrapper::ElementWrapperPrivate
22{
23public:
24 QDomElement element;
25 QDomDocument ownerDoc;
26 mutable QString xmlBase;
27 mutable bool xmlBaseParsed;
28 mutable QString xmlLang;
29 mutable bool xmlLangParsed;
30};
31
32ElementWrapper::ElementWrapper()
33 : d(new ElementWrapperPrivate)
34{
35 d->xmlBaseParsed = true;
36 d->xmlLangParsed = true;
37}
38
39ElementWrapper::ElementWrapper(const ElementWrapper &other)
40{
41 *this = other;
42}
43
44ElementWrapper::ElementWrapper(const QDomElement &element)
45 : d(new ElementWrapperPrivate)
46{
47 d->element = element;
48 d->ownerDoc = element.ownerDocument(); // keep a copy of the (shared, thus cheap) document around to ensure the element isn't deleted too early (Bug 190068)
49 d->xmlBaseParsed = false;
50 d->xmlLangParsed = false;
51}
52
53ElementWrapper::~ElementWrapper()
54{
55}
56
57ElementWrapper &ElementWrapper::operator=(const ElementWrapper &other)
58{
59 d = other.d;
60 return *this;
61}
62
63bool ElementWrapper::operator==(const ElementWrapper &other) const
64{
65 return d->element == other.d->element;
66}
67
68bool ElementWrapper::isNull() const
69{
70 return d->element.isNull();
71}
72
73const QDomElement &ElementWrapper::element() const
74{
75 return d->element;
76}
77
78QString ElementWrapper::xmlBase() const
79{
80 if (!d->xmlBaseParsed) { // xmlBase not computed yet
81 QDomElement current = d->element;
82
83 /*
84 An atom feed can contain nested xml:base elements, like this:
85
86 <feed xml:base="http://example.com/foo.atom">
87 <entry xml:base="subdir/">
88 <link href="foo.html"/>
89 </entry>
90 </feed>
91
92 To compute xml:base we explore the tree all the way up to the top.
93 `bases` stores all the xml:base values from the deepest element up to
94 the root element.
95 */
96 QStringList bases;
97 while (!current.isNull()) {
98 if (current.hasAttributeNS(xmlNamespace(), QStringLiteral("base"))) {
99 bases << current.attributeNS(xmlNamespace(), QStringLiteral("base"));
100 }
101
102 QDomNode parent = current.parentNode();
103
104 if (!parent.isNull() && parent.isElement()) {
105 current = parent.toElement();
106 } else {
107 current = QDomElement();
108 }
109 }
110 while (!bases.isEmpty()) {
111 QUrl u = QUrl(d->xmlBase).resolved(QUrl(bases.takeLast()));
112 d->xmlBase = u.url();
113 }
114
115 d->xmlBaseParsed = true;
116 }
117
118 return d->xmlBase;
119}
120
121QString ElementWrapper::completeURI(const QString &uri) const
122{
123 QUrl u = QUrl(xmlBase()).resolved(QUrl(uri));
124
125 if (u.isValid()) {
126 return u.url();
127 }
128
129 return uri;
130}
131
132QString ElementWrapper::xmlLang() const
133{
134 if (!d->xmlLangParsed) { // xmlLang not computed yet
135 QDomElement current = d->element;
136
137 while (!current.isNull()) {
138 if (current.hasAttributeNS(xmlNamespace(), QStringLiteral("lang"))) {
139 d->xmlLang = current.attributeNS(xmlNamespace(), QStringLiteral("lang"));
140 return d->xmlLang;
141 }
142
143 QDomNode parent = current.parentNode();
144
145 if (!parent.isNull() && parent.isElement()) {
146 current = parent.toElement();
147 } else {
148 current = QDomElement();
149 }
150 }
151 d->xmlLangParsed = true;
152 }
153 return d->xmlLang;
154}
155
156QString ElementWrapper::extractElementText(const QString &tagName) const
157{
158 const QDomElement el = d->element.namedItem(tagName).toElement();
159 return el.isNull() ? QString() : el.text().trimmed();
160}
161
162QString ElementWrapper::extractElementTextNS(const QString &namespaceURI, const QString &localName) const
163{
164 const QDomElement el = firstElementByTagNameNS(namespaceURI, localName);
165 return el.isNull() ? QString() : el.text().trimmed();
166}
167
168QString ElementWrapper::childNodesAsXML(const QDomElement &parent)
169{
170 ElementWrapper wrapper(parent);
171
172 if (parent.isNull()) {
173 return QString();
174 }
175
176 QDomNodeList list = parent.childNodes();
177
178 QString str;
180
181 // if there is a xml:base in our scope, first set it for
182 // each child element so the xml:base shows up in the
183 // serialization
184 QString base = wrapper.xmlBase();
185
186 for (int i = 0; i < list.count(); ++i) {
187 QDomNode it = list.item(i);
188 if (!base.isEmpty() //
189 && it.isElement() //
190 && !it.toElement().hasAttributeNS(xmlNamespace(), QStringLiteral("base"))) {
191 it.toElement().setAttributeNS(xmlNamespace(), QStringLiteral("base"), base);
192 }
193
194 ts << it;
195 }
196 return str.trimmed();
197}
198
199QString ElementWrapper::childNodesAsXML() const
200{
201 return childNodesAsXML(d->element);
202}
203
204QList<QDomElement> ElementWrapper::elementsByTagName(const QString &tagName) const
205{
206 QList<QDomElement> elements;
207 for (QDomNode n = d->element.firstChild(); !n.isNull(); n = n.nextSibling()) {
208 if (n.isElement()) {
209 QDomElement e = n.toElement();
210 if (e.tagName() == tagName) {
211 elements.append(e);
212 }
213 }
214 }
215 return elements;
216}
217
218QDomElement ElementWrapper::firstElementByTagNameNS(const QString &nsURI, const QString &localName) const
219{
220 if (isNull()) {
221 return QDomElement();
222 }
223
224 for (QDomNode n = d->element.firstChild(); !n.isNull(); n = n.nextSibling()) {
225 if (n.isElement()) {
226 QDomElement e = n.toElement();
227 if (e.localName() == localName && e.namespaceURI() == nsURI) {
228 return e;
229 }
230 }
231 }
232
233 return QDomElement();
234}
235
236QList<QDomElement> ElementWrapper::elementsByTagNameNS(const QString &nsURI, const QString &localName) const
237{
238 if (isNull()) {
239 return QList<QDomElement>();
240 }
241
242 QList<QDomElement> elements;
243 for (QDomNode n = d->element.firstChild(); !n.isNull(); n = n.nextSibling()) {
244 if (n.isElement()) {
245 QDomElement e = n.toElement();
246 if (e.localName() == localName && e.namespaceURI() == nsURI) {
247 elements.append(e);
248 }
249 }
250 }
251 return elements;
252}
253
254QString ElementWrapper::text() const
255{
256 return d->element.text();
257}
258
259QString ElementWrapper::attribute(const QString &name, const QString &defValue) const
260{
261 return d->element.attribute(name, defValue);
262}
263
264QString ElementWrapper::attributeNS(const QString &nsURI, const QString &localName, const QString &defValue) const
265{
266 return d->element.attributeNS(nsURI, localName, defValue);
267}
268
269bool ElementWrapper::hasAttribute(const QString &name) const
270{
271 return d->element.hasAttribute(name);
272}
273
274bool ElementWrapper::hasAttributeNS(const QString &nsURI, const QString &localName) const
275{
276 return d->element.hasAttributeNS(nsURI, localName);
277}
278
279} // namespace Syndication
KIOCORE_EXPORT QStringList list(const QString &fileClass)
QString attributeNS(const QString &nsURI, const QString &localName, const QString &defValue) const const
bool hasAttributeNS(const QString &nsURI, const QString &localName) const const
void setAttributeNS(const QString &nsURI, const QString &qName, const QString &value)
QString tagName() const const
QDomNodeList childNodes() const const
QDomNode firstChild() const const
bool isElement() const const
bool isNull() const const
QString localName() const const
QDomNode namedItem(const QString &name) const const
QString namespaceURI() const const
QDomDocument ownerDocument() const const
QDomNode parentNode() const const
QDomElement toElement() const const
void append(QList< T > &&value)
qsizetype count() const const
bool isEmpty() const const
value_type takeLast()
bool isEmpty() const const
QString trimmed() const const
bool isValid() const const
QUrl resolved(const QUrl &relative) const const
QString url(FormattingOptions options) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 17 2024 11:56:56 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.