00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "parser.h"
00024 #include "constants.h"
00025 #include "content.h"
00026 #include "document.h"
00027
00028 #include <documentsource.h>
00029
00030 #include <QtXml/QDomAttr>
00031 #include <QtXml/QDomDocument>
00032 #include <QtXml/QDomElement>
00033 #include <QtXml/QDomNamedNodeMap>
00034 #include <QtXml/QDomNode>
00035 #include <QtXml/QDomNodeList>
00036
00037 #include <QtCore/QHash>
00038 #include <QtCore/QRegExp>
00039 #include <QtCore/QString>
00040
00041 namespace Syndication {
00042 namespace Atom {
00043
00044 class Parser::ParserPrivate
00045 {
00046 public:
00047 static QDomDocument convertAtom0_3(const QDomDocument& document);
00048 static QDomNode convertNode(QDomDocument& doc, const QDomNode& node, const QHash<QString, QString>& nameMapper);
00049 };
00050
00051 bool Parser::accept(const Syndication::DocumentSource& source) const
00052 {
00053 QDomElement root = source.asDomDocument().documentElement();
00054 return !root.isNull() && (root.namespaceURI() == atom1Namespace() || root.namespaceURI() == atom0_3Namespace());
00055 }
00056
00057 Syndication::SpecificDocumentPtr Parser::parse(const Syndication::DocumentSource& source) const
00058 {
00059 QDomDocument doc = source.asDomDocument();
00060
00061 if (doc.isNull())
00062 {
00063
00064 return FeedDocumentPtr(new FeedDocument());
00065 }
00066
00067 QDomElement feed = doc.namedItem(QString::fromUtf8("feed")).toElement();
00068
00069 bool feedValid = !feed.isNull();
00070
00071 if (feedValid && feed.attribute(QString::fromUtf8("version"))
00072 == QString::fromUtf8("0.3"))
00073 {
00074 doc = ParserPrivate::convertAtom0_3(doc);
00075 feed = doc.namedItem(QString::fromUtf8("feed")).toElement();
00076
00077 }
00078
00079 feedValid = !feed.isNull() && feed.namespaceURI() == atom1Namespace();
00080
00081 if (feedValid)
00082 {
00083 return FeedDocumentPtr(new FeedDocument(feed));
00084 }
00085
00086 QDomElement entry = doc.namedItem(QString::fromUtf8("entry")).toElement();
00087 bool entryValid = !entry.isNull() && entry.namespaceURI() == atom1Namespace();
00088
00089 if (entryValid)
00090 {
00091 return EntryDocumentPtr(new EntryDocument(feed));
00092 }
00093
00094
00095 return FeedDocumentPtr(new FeedDocument());
00096 }
00097
00098 QString Parser::format() const
00099 {
00100 return QString::fromUtf8("atom");
00101 }
00102
00103 QDomNode Parser::ParserPrivate::convertNode(QDomDocument& doc, const QDomNode& node, const QHash<QString, QString>& nameMapper)
00104 {
00105 if (!node.isElement())
00106 return node.cloneNode(true);
00107
00108 bool isAtom03Element = node.namespaceURI() == atom0_3Namespace();
00109 QDomElement oldEl = node.toElement();
00110
00111
00112 QString newNS = isAtom03Element ? atom1Namespace() : node.namespaceURI();
00113
00114 QString newName = node.localName();
00115
00116
00117 if (isAtom03Element && nameMapper.contains(node.localName()))
00118 newName = nameMapper[node.localName()];
00119
00120 QDomElement newEl = doc.createElementNS(newNS, newName);
00121
00122 QDomNamedNodeMap attributes = oldEl.attributes();
00123
00124
00125 for (int i = 0; i < attributes.count(); ++i)
00126 {
00127 QDomAttr attr = attributes.item(i).toAttr();
00128 if (attr.namespaceURI().isEmpty())
00129 newEl.setAttribute(attr.name(), attr.value());
00130 else
00131 newEl.setAttributeNS(attr.namespaceURI(), attr.name(), attr.value());
00132 }
00133
00134 bool isTextConstruct = newNS == atom1Namespace()
00135 && (newName == QString::fromUtf8("title")
00136 || newName == QString::fromUtf8("rights")
00137 || newName == QString::fromUtf8("subtitle")
00138 || newName == QString::fromUtf8("summary"));
00139
00140
00141
00142 if (isTextConstruct)
00143 {
00144 QString oldType = newEl.attribute(QString::fromUtf8("type"), QString::fromUtf8("text/plain") );
00145 QString newType;
00146
00147 Content::Format format = Content::mapTypeToFormat(oldType);
00148 switch (format)
00149 {
00150 case Content::XML:
00151 newType = QString::fromUtf8("xhtml");
00152 break;
00153 case Content::EscapedHTML:
00154 newType = QString::fromUtf8("html");
00155 break;
00156 case Content::PlainText:
00157 case Content::Binary:
00158 default:
00159 newType = QString::fromUtf8("text");
00160
00161 }
00162
00163 newEl.setAttribute(QString::fromUtf8("type"), newType);
00164 }
00165 else
00166 {
00167
00168
00169 bool isGenerator = newNS == atom1Namespace() && newName == QString::fromUtf8("generator");
00170 if (isGenerator && newEl.hasAttribute(QString::fromUtf8("url")))
00171 newEl.setAttribute(QString::fromUtf8("uri"), newEl.attribute(QString::fromUtf8("url")));
00172 }
00173
00174
00175 QDomNodeList children = node.childNodes();
00176 for (int i = 0; i < children.count(); ++i)
00177 {
00178 newEl.appendChild(convertNode(doc, children.item(i), nameMapper));
00179 }
00180
00181 return newEl;
00182 }
00183
00184 QDomDocument Parser::ParserPrivate::convertAtom0_3(const QDomDocument& doc03)
00185 {
00186 QDomDocument doc = doc03.cloneNode(false).toDocument();
00187
00188
00189 QHash<QString, QString> nameMapper;
00190 nameMapper.insert(QString::fromUtf8("issued"), QString::fromUtf8("published"));
00191 nameMapper.insert(QString::fromUtf8("modified"), QString::fromUtf8("updated"));
00192 nameMapper.insert(QString::fromUtf8("url"), QString::fromUtf8("uri"));
00193 nameMapper.insert(QString::fromUtf8("copyright"), QString::fromUtf8("rights"));
00194 nameMapper.insert(QString::fromUtf8("tagline"), QString::fromUtf8("subtitle"));
00195
00196 QDomNodeList children = doc03.childNodes();
00197
00198 for (int i = 0; i < children.count(); ++i)
00199 {
00200 doc.appendChild(convertNode(doc, children.item(i), nameMapper));
00201 }
00202
00203 return doc;
00204 }
00205
00206 Parser::Parser() : d(0) {}
00207 Parser::~Parser() {}
00208 Parser::Parser(const Parser& other) : AbstractParser(other), d(0) {}
00209 Parser& Parser::operator=(const Parser& ) { return *this; }
00210
00211 }
00212 }