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
33 : d(new ElementWrapperPrivate)
34{
35 d->xmlBaseParsed = true;
36 d->xmlLangParsed = true;
37}
38
40{
41 *this = other;
42}
43
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
56
58{
59 d = other.d;
60 return *this;
61}
62
64{
65 return d->element == other.d->element;
66}
67
69{
70 return d->element.isNull();
71}
72
74{
75 return d->element;
76}
77
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
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
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
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
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
200{
201 return childNodesAsXML(d->element);
202}
203
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
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
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
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
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
A wrapper for XML elements.
const QDomElement & element() const
returns the wrapped resource.
bool hasAttributeNS(const QString &nsURI, const QString &localName) const
Returns true if this element has an attribute with the local name localName and the namespace URI nsU...
QString xmlBase() const
returns the xml:base value to be used for the wrapped element.
QString text() const
Returns the wrapped element's text or an empty string.
QString extractElementText(const QString &tagName) const
extracts the text from a child element, ignoring namespaces.
QDomElement firstElementByTagNameNS(const QString &nsURI, const QString &tagName) const
searches the direct children of the wrapped element for an element with a given namespace and tag nam...
bool operator==(const ElementWrapper &other) const
compares two wrappers.
ElementWrapper()
creates a element wrapper wrapping a null element.
QString completeURI(const QString &uri) const
completes relative URIs with a prefix specified via xml:base.
bool isNull() const
returns whether the wrapped element is a null element
bool hasAttribute(const QString &name) const
Returns true if this element has an attribute called name; otherwise returns false.
QString xmlLang() const
returns the xml:lang value to be used for the wrapped element.
QString childNodesAsXML() const
returns the child nodes of the wrapped element as XML.
QList< QDomElement > elementsByTagName(const QString &tagName) const
returns all child elements with tag name tagName Contrary to QDomElement::elementsByTagName() only di...
QList< QDomElement > elementsByTagNameNS(const QString &nsURI, const QString &tagName) const
returns all child elements with tag name tagname and namespace URI nsURI.
ElementWrapper & operator=(const ElementWrapper &other)
Assigns another element wrapper to this one.
QString attribute(const QString &name, const QString &defValue=QString()) const
Returns the attribute called name.
QString extractElementTextNS(const QString &namespaceURI, const QString &localName) const
extracts the text from a child element, respecting namespaces.
virtual ~ElementWrapper()
destructor
QString attributeNS(const QString &nsURI, const QString &localName, const QString &defValue=QString()) const
Returns the attribute with the local name localName and the namespace URI nsURI.
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
QString text() const const
QDomNodeList childNodes() const const
bool isElement() const const
bool isNull() const const
QString localName() 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 Mon Nov 18 2024 12:09:18 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.