void GenericNamespaceResolver::addBinding(const QXmlName nb) { if(nb.namespaceURI() == StandardNamespaces::UndeclarePrefix) m_bindings.remove(nb.prefix()); else m_bindings.insert(nb.prefix(), nb.namespaceURI()); }
void tst_QXmlSchemaValidator::resetSchemaNamePool() const { QXmlSchema schema1; QXmlNamePool np1 = schema1.namePool(); const QXmlName name1(np1, QLatin1String("localName"), QLatin1String("http://example.com/"), QLatin1String("prefix")); QXmlSchemaValidator validator(schema1); { QXmlNamePool compNamePool(validator.namePool()); QCOMPARE(name1.namespaceUri(compNamePool), QString::fromLatin1("http://example.com/")); QCOMPARE(name1.localName(compNamePool), QString::fromLatin1("localName")); QCOMPARE(name1.prefix(compNamePool), QString::fromLatin1("prefix")); } QXmlSchema schema2; QXmlNamePool np2 = schema2.namePool(); const QXmlName name2(np2, QLatin1String("remoteName"), QLatin1String("http://example.com/"), QLatin1String("suffix")); // make sure that after re-setting the schema, the new namepool is used validator.setSchema(schema2); { QXmlNamePool compNamePool(validator.namePool()); QCOMPARE(name2.namespaceUri(compNamePool), QString::fromLatin1("http://example.com/")); QCOMPARE(name2.localName(compNamePool), QString::fromLatin1("remoteName")); QCOMPARE(name2.prefix(compNamePool), QString::fromLatin1("suffix")); } }
void AccelTreeBuilder<FromDocument>::namespaceBinding(const QXmlName &nb) { /* Note, because attribute() sometimes generate namespaceBinding() calls, this function * can be called after attributes, in contrast to what the class documentation says. This is ok, * as long as we're not dealing with public API. */ /* If we've received attributes, it means the element's size have changed and m_preNumber have advanced, * so "reverse back" to the actual element. */ const AccelTree::PreNumber pn = m_preNumber - m_size.top(); QVector<QXmlName> &nss = m_document->namespaces[pn]; /* "xml" hasn't been declared for each node, AccelTree::namespaceBindings() adds it, so avoid it * such that we don't get duplicates. */ if(nb.prefix() == StandardPrefixes::xml) return; /* If we already have the binding, skip it. */ const int len = nss.count(); for(int i = 0; i < len; ++i) { if(nss.at(i).prefix() == nb.prefix()) return; } nss.append(nb); }
void ComputedNamespaceConstructor::evaluateToSequenceReceiver(const DynamicContext::Ptr &context) const { const Item prefixItem(m_operand1->evaluateSingleton(context)); const QString prefix(prefixItem ? prefixItem.stringValue() : QString()); const Item namespaceItem(m_operand2->evaluateSingleton(context)); const QString namespaceURI(namespaceItem ? namespaceItem.stringValue() : QString()); if(namespaceURI.isEmpty()) { context->error(QtXmlPatterns::tr("In a namespace constructor, the value for a namespace cannot be an empty string."), ReportContext::XTDE0930, this); } /* One optimization could be to store a pointer to * the name pool as a member in order to avoid the virtual call(s). */ const NamePool::Ptr np(context->namePool()); if(!prefix.isEmpty() && !QXmlUtils::isNCName(prefix)) { context->error(QtXmlPatterns::tr("The prefix must be a valid %1, which %2 is not.") .arg(formatType(np, BuiltinTypes::xsNCName), formatKeyword(prefix)), ReportContext::XTDE0920, this); } const QXmlName binding(np->allocateBinding(prefix, namespaceURI)); AnyURI::toQUrl<ReportContext::XTDE0905, DynamicContext::Ptr>(namespaceURI, context, this); if(binding.prefix() == StandardPrefixes::xmlns) { context->error(QtXmlPatterns::tr("The prefix %1 cannot be bound.") .arg(formatKeyword(prefix)), ReportContext::XTDE0920, this); } if((binding.prefix() == StandardPrefixes::xml && binding.namespaceURI() != StandardNamespaces::xml) || (binding.prefix() != StandardPrefixes::xml && binding.namespaceURI() == StandardNamespaces::xml)) { context->error(QtXmlPatterns::tr("Only the prefix %1 can be bound to %2 and vice versa.") .arg(formatKeyword(prefix), formatKeyword(namespaceURI)), ReportContext::XTDE0925, this); } context->outputReceiver()->namespaceBinding(binding); }
/*! Check that functions have the correct const qualification. */ void tst_QXmlName::constCorrectness() const { const QXmlName name; /* isNull() */ QVERIFY(name.isNull()); /* operator==() */ QVERIFY(name == name); /* operator!=() */ QVERIFY(!(name != name)); QXmlNamePool namePool; const QXmlName name2(namePool, QLatin1String("localName"), QLatin1String("http://example.com/"), QLatin1String("prefix")); /* namespaceUri(). */ QCOMPARE(name2.namespaceUri(namePool), QLatin1String("http://example.com/")); /* localName(). */ QCOMPARE(name2.localName(namePool), QLatin1String("localName")); /* prefix(). */ QCOMPARE(name2.prefix(namePool), QLatin1String("prefix")); /* toClarkname(). */ QCOMPARE(name2.toClarkName(namePool), QLatin1String("{http://example.com/}prefix:localName")); }
/*! \reimp */ void QXmlSerializer::attribute(const QXmlName &name, const QStringRef &value) { Q_D(QXmlSerializer); Q_ASSERT(!name.isNull()); /* Ensure that the namespace URI used in the name gets outputted. */ { /* Since attributes doesn't pick up the default namespace, a * namespace declaration would cause trouble if we output it. */ if(name.prefix() != StandardPrefixes::empty) namespaceBinding(name); } if(atDocumentRoot()) { Q_UNUSED(d); d->query.d->staticContext()->error(QtXmlPatterns::tr( "Attribute %1 can't be serialized because it appears at " "the top level.").arg(formatKeyword(d->np, name)), ReportContext::SENR0001, d->query.d->expression().data()); } else { d->write(' '); write(name); write("=\""); writeEscapedAttribute(value.toString()); d->write('"'); } }
void AccelTreeBuilder<FromDocument>::startElement(const QXmlName &name, qint64 line, qint64 column) { startStructure(); AccelTree::BasicNodeData data(currentDepth(), currentParent(), QXmlNodeModelIndex::Element, -1, name); m_document->basicData.append(data); if (m_features & SourceLocationsFeature) m_document->sourcePositions.insert(m_document->maximumPreNumber(), qMakePair(line, column)); ++m_preNumber; m_ancestors.push(m_preNumber); ++m_size.top(); m_size.push(0); /* With node constructors, we can receive names for which we have no namespace * constructors, such as in the query '<xs:space/>'. Since the 'xs' prefix has no * NamespaceConstructor in this case, we synthesize the namespace. * * In case we're constructing from an XML document we avoid the call because * although it's redundant, it's on extra virtual call for each element. */ if(!FromDocument) namespaceBinding(QXmlName(name.namespaceURI(), 0, name.prefix())); m_isPreviousAtomic = false; }
/*! \internal */ bool QXmlSerializer::isBindingInScope(const QXmlName nb) const { Q_D(const QXmlSerializer); const int levelLen = d->namespaces.size(); if(nb.prefix() == StandardPrefixes::empty) { for(int lvl = levelLen - 1; lvl >= 0; --lvl) { const QVector<QXmlName> &scope = d->namespaces.at(lvl); const int vectorLen = scope.size(); for(int s = vectorLen - 1; s >= 0; --s) { const QXmlName &nsb = scope.at(s); if(nsb.prefix() == StandardPrefixes::empty) return nsb.namespaceURI() == nb.namespaceURI(); } } } else { for(int lvl = 0; lvl < levelLen; ++lvl) { const QVector<QXmlName> &scope = d->namespaces.at(lvl); const int vectorLen = scope.size(); for(int s = 0; s < vectorLen; ++s) { const QXmlName &n = scope.at(s); if (n.prefix() == nb.prefix() && n.namespaceURI() == nb.namespaceURI()) return true; } } } return false; }
/*! \reimp */ void QXmlSerializer::namespaceBinding(const QXmlName &nb) { /* * Writes out \a nb. * * Namespace bindings aren't looked up in a cache, because * we typically receive very few. */ Q_D(QXmlSerializer); Q_ASSERT_X(!nb.isNull(), Q_FUNC_INFO, "It makes no sense to pass a null QXmlName."); Q_ASSERT_X((nb.namespaceURI() != StandardNamespaces::empty) || (nb.prefix() == StandardPrefixes::empty), Q_FUNC_INFO, "Undeclarations of prefixes aren't allowed in XML 1.0 " "and aren't supposed to be received."); if(nb.namespaceURI() == QPatternist::StandardNamespaces::StopNamespaceInheritance) return; if(isBindingInScope(nb)) return; d->namespaces.top().append(nb); if(nb.prefix() == StandardPrefixes::empty) write(" xmlns"); else { write(" xmlns:"); write(d->np->stringForPrefix(nb.prefix())); } write("=\""); writeEscapedAttribute(d->np->stringForNamespace(nb.namespaceURI())); d->write('"'); }
void tst_QSimpleXmlNodeModel::namePool() const { /* Check that the name pool we pass in, is what actually is returned. */ QXmlNamePool np; const QXmlName name(np, QLatin1String("localName"), QLatin1String("http://example.com/XYZ"), QLatin1String("prefix432")); TestSimpleNodeModel model(np); const QXmlNamePool np2(model.namePool()); /* If it's a bug, this will more or less crash. */ QCOMPARE(name.namespaceUri(np2), QString::fromLatin1("http://example.com/XYZ")); QCOMPARE(name.localName(np2), QString::fromLatin1("localName")); QCOMPARE(name.prefix(np2), QString::fromLatin1("prefix432")); }
void tst_QXmlSchema::constructorQXmlNamePool() const { QXmlSchema schema; QXmlNamePool np = schema.namePool(); const QXmlName name(np, QLatin1String("localName"), QLatin1String("http://example.com/"), QLatin1String("prefix")); QXmlNamePool np2(schema.namePool()); QCOMPARE(name.namespaceUri(np2), QString::fromLatin1("http://example.com/")); QCOMPARE(name.localName(np2), QString::fromLatin1("localName")); QCOMPARE(name.prefix(np2), QString::fromLatin1("prefix")); // make sure namePool() is const const QXmlSchema constSchema; np = constSchema.namePool(); }
QString NamePool::toClarkName(const QXmlName &name) const { if(name.isNull()) return QLatin1String("QXmlName(null)"); else { if(name.hasNamespace()) { const QString ns(stringForNamespace(name.namespaceURI())); const QString p(stringForPrefix(name.prefix())); const QString l(stringForLocalName(name.localName())); return QChar::fromLatin1('{') + ns + QChar::fromLatin1('}') + (p.isEmpty() ? l : p + QChar::fromLatin1(':') + l); } else return stringForLocalName(name.localName()); } }
void tst_QXmlSchemaValidator::constructorQXmlNamePool() const { // test that the name pool from the schema is used by // the schema validator as well QXmlSchema schema; QXmlNamePool np = schema.namePool(); const QXmlName name(np, QLatin1String("localName"), QLatin1String("http://example.com/"), QLatin1String("prefix")); QXmlSchemaValidator validator(schema); QXmlNamePool np2(validator.namePool()); QCOMPARE(name.namespaceUri(np2), QString::fromLatin1("http://example.com/")); QCOMPARE(name.localName(np2), QString::fromLatin1("localName")); QCOMPARE(name.prefix(np2), QString::fromLatin1("prefix")); // make sure namePool() is const const QXmlSchemaValidator constValidator(schema); np = constValidator.namePool(); }
void AccelTreeBuilder<FromDocument>::attribute(const QXmlName &name, const QStringRef &value) { /* Attributes adds a namespace binding, so lets synthesize one. * * We optimize by checking whether we have a namespace for which a binding would * be generated. Happens relatively rarely. */ if(name.hasPrefix()) namespaceBinding(QXmlName(name.namespaceURI(), 0, name.prefix())); m_document->basicData.append(AccelTree::BasicNodeData(currentDepth(), currentParent(), QXmlNodeModelIndex::Attribute, 0, name)); ++m_preNumber; ++m_size.top(); m_isPreviousAtomic = false; if(name.namespaceURI() == StandardNamespaces::xml && name.localName() == StandardLocalNames::id) { const QString normalized(value.toString().simplified()); if(QXmlUtils::isNCName(normalized)) { const QXmlName::LocalNameCode id = m_namePool->allocateLocalName(normalized); const int oldSize = m_document->m_IDs.count(); m_document->m_IDs.insert(id, currentParent()); /* We don't run the value through m_attributeCompress here, because * the likelyhood of it deing identical to another attribute is * very small. */ m_document->data.insert(m_preNumber, normalized); /** * In the case that we're called for doc-available(), m_context is * null, and we need to flag somehow that we failed to load this * document. */ if(oldSize == m_document->m_IDs.count() && m_context) // TODO { Q_ASSERT(m_context); m_context->error(QtXmlPatterns::tr("An %1-attribute with value %2 has already been declared.") .arg(formatKeyword("xml:id"), formatData(normalized)), FromDocument ? ReportContext::FODC0002 : ReportContext::XQDY0091, this); } } else if(m_context) // TODO { Q_ASSERT(m_context); /* If we're building from an XML Document(e.g, we're fed from QXmlStreamReader, we raise FODC0002, * otherwise XQDY0091. */ m_context->error(QtXmlPatterns::tr("An %1-attribute must have a " "valid %2 as value, which %3 isn't.").arg(formatKeyword("xml:id"), formatType(m_namePool, BuiltinTypes::xsNCName), formatData(value.toString())), FromDocument ? ReportContext::FODC0002 : ReportContext::XQDY0091, this); } } else m_document->data.insert(m_preNumber, *m_attributeCompress.insert(value.toString())); }
void AccelTree::copyNodeTo(const QXmlNodeModelIndex &node, QAbstractXmlReceiver *const receiver, const NodeCopySettings &settings) const { /* This code piece can be seen as a customized version of * QAbstractXmlReceiver::item/sendAsNode(). */ Q_ASSERT(receiver); Q_ASSERT(!node.isNull()); typedef QHash<QXmlName::PrefixCode, QXmlName::NamespaceCode> Binding; QStack<Binding> outputted; switch(node.kind()) { case QXmlNodeModelIndex::Element: { outputted.push(Binding()); /* Add the namespace for our element name. */ const QXmlName elementName(node.name()); receiver->startElement(elementName); if(!settings.testFlag(InheritNamespaces)) receiver->namespaceBinding(QXmlName(StandardNamespaces::StopNamespaceInheritance, 0, StandardPrefixes::StopNamespaceInheritance)); if(settings.testFlag(PreserveNamespaces)) node.sendNamespaces(receiver); else { /* Find the namespaces that we actually use and add them to outputted. These are drawn * from the element name, and the node's attributes. */ outputted.top().insert(elementName.prefix(), elementName.namespaceURI()); const QXmlNodeModelIndex::Iterator::Ptr attributes(iterate(node, QXmlNodeModelIndex::AxisAttribute)); QXmlNodeModelIndex attr(attributes->next()); while(!attr.isNull()) { const QXmlName &attrName = attr.name(); outputted.top().insert(attrName.prefix(), attrName.namespaceURI()); attr = attributes->next(); } Binding::const_iterator it(outputted.top().constBegin()); const Binding::const_iterator end(outputted.top().constEnd()); for(; it != end; ++it) receiver->namespaceBinding(QXmlName(it.value(), 0, it.key())); } /* Send the attributes of the element. */ { QXmlNodeModelIndex::Iterator::Ptr attributes(node.iterate(QXmlNodeModelIndex::AxisAttribute)); QXmlNodeModelIndex attribute(attributes->next()); while(!attribute.isNull()) { const QString &v = attribute.stringValue(); receiver->attribute(attribute.name(), QStringRef(&v)); attribute = attributes->next(); } } /* Send the children of the element. */ copyChildren(node, receiver, settings); receiver->endElement(); outputted.pop(); break; } case QXmlNodeModelIndex::Document: { /* We need to intercept and grab the elements of the document node, such * that we preserve/inherit preference applies to them. */ receiver->startDocument(); copyChildren(node, receiver, settings); receiver->endDocument(); break; } default: receiver->item(node); } }