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 <QStringList>
16 #include <QTextStream>
17 
18 namespace Syndication
19 {
20 class ElementWrapper::ElementWrapperPrivate
21 {
22 public:
24  QDomDocument ownerDoc;
25  mutable QString xmlBase;
26  mutable bool xmlBaseParsed;
27  mutable QString xmlLang;
28  mutable bool xmlLangParsed;
29 };
30 
32  : d(new ElementWrapperPrivate)
33 {
34  d->xmlBaseParsed = true;
35  d->xmlLangParsed = true;
36 }
37 
39 {
40  *this = other;
41 }
42 
44  : d(new ElementWrapperPrivate)
45 {
46  d->element = element;
47  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)
48  d->xmlBaseParsed = false;
49  d->xmlLangParsed = false;
50 }
51 
53 {
54 }
55 
57 {
58  d = other.d;
59  return *this;
60 }
61 
63 {
64  return d->element == other.d->element;
65 }
66 
68 {
69  return d->element.isNull();
70 }
71 
73 {
74  return d->element;
75 }
76 
78 {
79  if (!d->xmlBaseParsed) { // xmlBase not computed yet
80  QDomElement current = d->element;
81 
82  /*
83  An atom feed can contain nested xml:base elements, like this:
84 
85  <feed xml:base="http://example.com/foo.atom">
86  <entry xml:base="subdir/">
87  <link href="foo.html"/>
88  </entry>
89  </feed>
90 
91  To compute xml:base we explore the tree all the way up to the top.
92  `bases` stores all the xml:base values from the deepest element up to
93  the root element.
94  */
95  QStringList bases;
96  while (!current.isNull()) {
97  if (current.hasAttributeNS(xmlNamespace(), QStringLiteral("base"))) {
98  bases << current.attributeNS(xmlNamespace(), QStringLiteral("base"));
99  }
100 
101  QDomNode parent = current.parentNode();
102 
103  if (!parent.isNull() && parent.isElement()) {
104  current = parent.toElement();
105  } else {
106  current = QDomElement();
107  }
108  }
109  while (!bases.isEmpty()) {
110  QUrl u = QUrl(d->xmlBase).resolved(QUrl(bases.takeLast()));
111  d->xmlBase = u.url();
112  }
113 
114  d->xmlBaseParsed = true;
115  }
116 
117  return d->xmlBase;
118 }
119 
121 {
122  QUrl u = QUrl(xmlBase()).resolved(QUrl(uri));
123 
124  if (u.isValid()) {
125  return u.url();
126  }
127 
128  return uri;
129 }
130 
132 {
133  if (!d->xmlLangParsed) { // xmlLang not computed yet
134  QDomElement current = d->element;
135 
136  while (!current.isNull()) {
137  if (current.hasAttributeNS(xmlNamespace(), QStringLiteral("lang"))) {
138  d->xmlLang = current.attributeNS(xmlNamespace(), QStringLiteral("lang"));
139  return d->xmlLang;
140  }
141 
142  QDomNode parent = current.parentNode();
143 
144  if (!parent.isNull() && parent.isElement()) {
145  current = parent.toElement();
146  } else {
147  current = QDomElement();
148  }
149  }
150  d->xmlLangParsed = true;
151  }
152  return d->xmlLang;
153 }
154 
156 {
157  const QDomElement el = d->element.namedItem(tagName).toElement();
158  return el.isNull() ? QString() : el.text().trimmed();
159 }
160 
161 QString ElementWrapper::extractElementTextNS(const QString &namespaceURI, const QString &localName) const
162 {
163  const QDomElement el = firstElementByTagNameNS(namespaceURI, localName);
164  return el.isNull() ? QString() : el.text().trimmed();
165 }
166 
168 {
169  ElementWrapper wrapper(parent);
170 
171  if (parent.isNull()) {
172  return QString();
173  }
174 
175  QDomNodeList list = parent.childNodes();
176 
177  QString str;
179 
180  // if there is a xml:base in our scope, first set it for
181  // each child element so the xml:base shows up in the
182  // serialization
183  QString base = wrapper.xmlBase();
184 
185  for (int i = 0; i < list.count(); ++i) {
186  QDomNode it = list.item(i);
187  if (!base.isEmpty() //
188  && it.isElement() //
189  && !it.toElement().hasAttributeNS(xmlNamespace(), QStringLiteral("base"))) {
190  it.toElement().setAttributeNS(xmlNamespace(), QStringLiteral("base"), base);
191  }
192 
193  ts << it;
194  }
195  return str.trimmed();
196 }
197 
199 {
200  return childNodesAsXML(d->element);
201 }
202 
204 {
205  QList<QDomElement> elements;
206  for (QDomNode n = d->element.firstChild(); !n.isNull(); n = n.nextSibling()) {
207  if (n.isElement()) {
208  QDomElement e = n.toElement();
209  if (e.tagName() == tagName) {
210  elements.append(e);
211  }
212  }
213  }
214  return elements;
215 }
216 
218 {
219  if (isNull()) {
220  return QDomElement();
221  }
222 
223  for (QDomNode n = d->element.firstChild(); !n.isNull(); n = n.nextSibling()) {
224  if (n.isElement()) {
225  QDomElement e = n.toElement();
226  if (e.localName() == localName && e.namespaceURI() == nsURI) {
227  return e;
228  }
229  }
230  }
231 
232  return QDomElement();
233 }
234 
236 {
237  if (isNull()) {
238  return QList<QDomElement>();
239  }
240 
241  QList<QDomElement> elements;
242  for (QDomNode n = d->element.firstChild(); !n.isNull(); n = n.nextSibling()) {
243  if (n.isElement()) {
244  QDomElement e = n.toElement();
245  if (e.localName() == localName && e.namespaceURI() == nsURI) {
246  elements.append(e);
247  }
248  }
249  }
250  return elements;
251 }
252 
254 {
255  return d->element.text();
256 }
257 
258 QString ElementWrapper::attribute(const QString &name, const QString &defValue) const
259 {
260  return d->element.attribute(name, defValue);
261 }
262 
263 QString ElementWrapper::attributeNS(const QString &nsURI, const QString &localName, const QString &defValue) const
264 {
265  return d->element.attributeNS(nsURI, localName, defValue);
266 }
267 
268 bool ElementWrapper::hasAttribute(const QString &name) const
269 {
270  return d->element.hasAttribute(name);
271 }
272 
273 bool ElementWrapper::hasAttributeNS(const QString &nsURI, const QString &localName) const
274 {
275  return d->element.hasAttributeNS(nsURI, localName);
276 }
277 
278 } // namespace Syndication
QString attribute(const QString &name, const QString &defValue=QString()) const
Returns the attribute called name.
QString url(QUrl::FormattingOptions options) 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 text() const
Returns the wrapped element&#39;s text or an empty string.
QDomNode item(int index) const const
QList< QDomElement > elementsByTagName(const QString &tagName) const
returns all child elements with tag name tagName Contrary to QDomElement::elementsByTagName() only di...
ElementWrapper()
creates a element wrapper wrapping a null element.
A wrapper for XML elements.
QString attributeNS(const QString nsURI, const QString &localName, const QString &defValue) const const
ElementWrapper & operator=(const ElementWrapper &other)
Assigns another element wrapper to this one.
bool hasAttributeNS(const QString &nsURI, const QString &localName) const const
bool isElement() const const
QString childNodesAsXML() const
returns the child nodes of the wrapped element as XML.
QString namespaceURI() const const
bool hasAttribute(const QString &name) const
Returns true if this element has an attribute called name; otherwise returns false.
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...
QDomNodeList childNodes() const const
QString extractElementText(const QString &tagName) const
extracts the text from a child element, ignoring namespaces.
bool operator==(const ElementWrapper &other) const
compares two wrappers.
QDomElement toElement() const const
void setAttributeNS(const QString nsURI, const QString &qName, const QString &value)
int count() const const
void append(const T &value)
QString localName() const const
QDomDocument ownerDocument() const const
QString text() const const
bool isEmpty() const const
bool isEmpty() const const
QString trimmed() const const
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...
bool isNull() const
returns whether the wrapped element is a null element
QString completeURI(const QString &uri) const
completes relative URIs with a prefix specified via xml:base.
bool isNull() const const
T takeLast()
bool isValid() const const
QDomNode parentNode() const const
QString xmlLang() const
returns the xml:lang value to be used for the wrapped element.
QUrl resolved(const QUrl &relative) const const
const QDomElement & element() const
returns the wrapped resource.
QString extractElementTextNS(const QString &namespaceURI, const QString &localName) const
extracts the text from a child element, respecting namespaces.
QString tagName() 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.
bool isNull() const const
virtual ~ElementWrapper()
destructor
QString xmlBase() const
returns the xml:base value to be used for the wrapped element.
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Oct 16 2021 23:04:27 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.