Syndication

elementwrapper.cpp
1 /*
2  This file is part of the syndication library
3  SPDX-FileCopyrightText: 2006 Frank Osterfeld <[email protected]>
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 
19 namespace Syndication
20 {
21 class ElementWrapper::ElementWrapperPrivate
22 {
23 public:
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 
54 {
55 }
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 
162 QString 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 
259 QString ElementWrapper::attribute(const QString &name, const QString &defValue) const
260 {
261  return d->element.attribute(name, defValue);
262 }
263 
264 QString ElementWrapper::attributeNS(const QString &nsURI, const QString &localName, const QString &defValue) const
265 {
266  return d->element.attributeNS(nsURI, localName, defValue);
267 }
268 
269 bool ElementWrapper::hasAttribute(const QString &name) const
270 {
271  return d->element.hasAttribute(name);
272 }
273 
274 bool ElementWrapper::hasAttributeNS(const QString &nsURI, const QString &localName) const
275 {
276  return d->element.hasAttributeNS(nsURI, localName);
277 }
278 
279 } // namespace Syndication
void append(const T &value)
QString text() const const
QDomElement toElement() const const
bool isNull() const const
QString extractElementText(const QString &tagName) const
extracts the text from a child element, ignoring namespaces.
QString tagName() const const
bool hasAttribute(const QString &name) const
Returns true if this element has an attribute called name; otherwise returns false.
QDomNode parentNode() const const
int count(const T &value) const const
bool isNull() const const
ElementWrapper()
creates a element wrapper wrapping a null element.
A wrapper for XML elements.
QString trimmed() const const
QString url(QUrl::FormattingOptions options) const const
ElementWrapper & operator=(const ElementWrapper &other)
Assigns another element wrapper to this one.
QString attributeNS(const QString nsURI, const QString &localName, const QString &defValue) const const
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 namespaceURI() const const
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...
QString xmlBase() const
returns the xml:base value to be used for the wrapped element.
bool isValid() const const
QList< QDomElement > elementsByTagNameNS(const QString &nsURI, const QString &tagName) const
returns all child elements with tag name tagname and namespace URI nsURI.
QString localName() const const
bool isEmpty() const const
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.
QDomDocument ownerDocument() const const
bool isNull() const
returns whether the wrapped element is a null element
bool hasAttributeNS(const QString &nsURI, const QString &localName) const const
bool isEmpty() const const
bool operator==(const ElementWrapper &other) const
compares two wrappers.
QDomNodeList childNodes() const const
QUrl resolved(const QUrl &relative) const const
QString text() const
Returns the wrapped element's text or an empty string.
QList< QDomElement > elementsByTagName(const QString &tagName) const
returns all child elements with tag name tagName Contrary to QDomElement::elementsByTagName() only di...
QString childNodesAsXML() const
returns the child nodes of the wrapped element as XML.
void setAttributeNS(const QString nsURI, const QString &qName, const QString &value)
QString xmlLang() const
returns the xml:lang value to be used for the wrapped element.
QString completeURI(const QString &uri) const
completes relative URIs with a prefix specified via xml:base.
bool isElement() const const
T takeLast()
const QDomElement & element() const
returns the wrapped resource.
virtual ~ElementWrapper()
destructor
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...
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Thu Aug 11 2022 03:59:30 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.