PendingUpdateList UReplaceValueOf::createUpdateList(DynamicContext *context) const { Node::Ptr node = (Node*)target_->createResult(context)->next(context).get(); if(node->dmNodeKind() == Node::document_string) XQThrow(XPath2TypeMatchException,X("UReplaceValueOf::createUpdateList"), X("The target expression of a replace expression does not return a single " "node that is not a document node [err:XUTY0008]")); XMLBuffer buf; XQDOMConstructor::getStringValue(expr_, buf, context); // If $target is a comment node, and $string contains two adjacent hyphens or ends with a hyphen, a dynamic error is raised [err:XQDY0072]. if(node->dmNodeKind() == Node::comment_string) { bool foundOne = false; for(const XMLCh *str = buf.getRawBuffer(); *str; ++str) { if(*str == '-') { if(foundOne) { XQThrow(DynamicErrorException,X("UReplaceValueOf::createUpdateList"), X("The replace value of expression would result in a comment node whose content contains two adjacent hyphens [err:XQDY0072]")); } else foundOne = true; } else { foundOne = false; } } if(foundOne) { XQThrow(DynamicErrorException,X("UReplaceValueOf::createUpdateList"), X("The replace value of expression would result in a comment node whose content ends with a hyphen [err:XQDY0072]")); } } // If $target is a processing instruction node, and $string contains the substring "?>", a dynamic error is raised [err:XQDY0026]. else if(node->dmNodeKind() == Node::processing_instruction_string) { bool foundQuestion = false; for(const XMLCh *str = buf.getRawBuffer(); *str; ++str) { if(*str == '?') { foundQuestion = true; } else { if(foundQuestion && *str == '>') { XQThrow(DynamicErrorException,X("UReplaceValueOf::createUpdateList"), X("The replace value of expression would result in a processing instruction node whose content includes the string \"?>\" [err:XQDY0026]")); } foundQuestion = false; } } } Item::Ptr value = context->getItemFactory()->createString(buf.getRawBuffer(), context); if(node->dmNodeKind() == Node::element_string) { return PendingUpdate(PendingUpdate::REPLACE_ELEMENT_CONTENT, node, value, this); } else { return PendingUpdate(PendingUpdate::REPLACE_VALUE, node, value, this); } }
PendingUpdateList UInsertAsLast::createUpdateList(DynamicContext *context) const { Node::Ptr node = (Node*)target_->createResult(context)->next(context).get(); if(node->dmNodeKind() != Node::element_string && node->dmNodeKind() != Node::document_string) XQThrow(XPath2TypeMatchException,X("UInsertAsLast::createUpdateList"), X("It is a type error for the target expression of an insert as last expression not to be a single element " "or document [err:XUTY0005]")); Sequence alist(context->getMemoryManager()); Sequence clist(context->getMemoryManager()); Result value = source_->createResult(context); Item::Ptr item; while((item = value->next(context)).notNull()) { if(((Node*)item.get())->dmNodeKind() == Node::attribute_string) { if(!clist.isEmpty()) XQThrow(ASTException,X("UInsertAsLast::createUpdateList"), X("Attribute nodes must occur before other nodes in the source expression for an insert as last expression [err:XUTY0004]")); // b. No attribute node in $alist may have a QName whose implied namespace binding conflicts with a namespace // binding in the "namespaces" property of $target [err:XUDY0023]. ATQNameOrDerived::Ptr qname = ((Node*)item.get())->dmNodeName(context); if(qname->getURI() != 0 && *(qname->getURI()) != 0) { ATAnyURIOrDerived::Ptr uri = FunctionNamespaceURIForPrefix::uriForPrefix(qname->getPrefix(), node, context, this); if(uri.notNull() && !XPath2Utils::equals(uri->asString(context), qname->getURI())) { XMLBuffer buf; buf.append(X("Implied namespace binding for the insert as last expression (\"")); buf.append(qname->getPrefix()); buf.append(X("\" -> \"")); buf.append(qname->getURI()); buf.append(X("\") conflicts with those already existing on the parent element of the target attribute [err:XUDY0023]")); XQThrow3(DynamicErrorException, X("UInsertInto::createUpdateList"), buf.getRawBuffer(), this); } } alist.addItem(item); } else clist.addItem(item); } PendingUpdateList result; if(!alist.isEmpty()) { // 3. If $alist is not empty and into is specified, the following checks are performed: // a. $target must be an element node [err:XUTY0022]. if(node->dmNodeKind() == Node::document_string) XQThrow(XPath2TypeMatchException,X("UInsertInto::createUpdateList"), X("It is a type error if an insert expression specifies the insertion of an attribute node into a document node [err:XUTY0022]")); result.addUpdate(PendingUpdate(PendingUpdate::INSERT_ATTRIBUTES, node, alist, this)); } if(!clist.isEmpty()) { result.addUpdate(PendingUpdate(PendingUpdate::INSERT_INTO_AS_LAST, node, clist, this)); } return result; }
PendingUpdateList URename::createUpdateList(DynamicContext *context) const { Node::Ptr node = (Node*)target_->createResult(context)->next(context).get(); if(node->dmNodeKind() != Node::element_string && node->dmNodeKind() != Node::attribute_string && node->dmNodeKind() != Node::processing_instruction_string) XQThrow(XPath2TypeMatchException,X("URename::createUpdateList"), X("It is a type error for the target expression of a rename expression not to be a single element, " "attribute or processing instruction [err:XUTY0012]")); ATQNameOrDerived::Ptr qname = (ATQNameOrDerived*)name_->createResult(context)->next(context).get(); // 3. The following checks are performed for error conditions: // a. If $target is an element node, the "namespaces" property of $target must not include any namespace binding that conflicts // with the implied namespace binding of $QName [err:XUDY0023]. if(node->dmNodeKind() == Node::element_string) { ATAnyURIOrDerived::Ptr uri = FunctionNamespaceURIForPrefix::uriForPrefix(qname->getPrefix(), node, context, this); if(uri.notNull() && !XPath2Utils::equals(uri->asString(context), qname->getURI())) { XMLBuffer buf; buf.append(X("Implied namespace binding for the rename expression (\"")); buf.append(qname->getPrefix()); buf.append(X("\" -> \"")); buf.append(qname->getURI()); buf.append(X("\") conflicts with those already existing on the target element [err:XUDY0023]")); XQThrow3(DynamicErrorException, X("URename::createUpdateList"), buf.getRawBuffer(), this); } } // b. If $target is an attribute node that has a parent, the "namespaces" property of parent($target) must not include any // namespace binding that conflicts with the implied namespace binding of $QName [err:XUDY0023]. else if(node->dmNodeKind() == Node::attribute_string) { Node::Ptr parentNode = node->dmParent(context); if(parentNode.notNull() && qname->getURI() != 0 && *(qname->getURI()) != 0) { ATAnyURIOrDerived::Ptr uri = FunctionNamespaceURIForPrefix::uriForPrefix(qname->getPrefix(), parentNode, context, this); if(uri.notNull() && !XPath2Utils::equals(uri->asString(context), qname->getURI())) { XMLBuffer buf; buf.append(X("Implied namespace binding for the rename expression (\"")); buf.append(qname->getPrefix()); buf.append(X("\" -> \"")); buf.append(qname->getURI()); buf.append(X("\") conflicts with those already existing on the parent element of the target attribute [err:XUDY0023]")); XQThrow3(DynamicErrorException, X("URename::createUpdateList"), buf.getRawBuffer(), this); } } } // c. If $target is processing instruction node, $QName must not include a non-empty namespace prefix. [err:XUDY0025]. else if(node->dmNodeKind() == Node::processing_instruction_string && !XPath2Utils::equals(qname->getPrefix(), XMLUni::fgZeroLenString)) XQThrow(XPath2TypeMatchException,X("URename::createUpdateList"), X("The target of a rename expression is a processing instruction node, and the new name " "expression returned a QName with a non-empty namespace prefix [err:XUDY0025]")); return PendingUpdate(PendingUpdate::RENAME, node, qname, this); }
void XercesUpdateFactory::applyReplaceAttribute(const PendingUpdate &update, DynamicContext *context) { const XercesNodeImpl *nodeImpl = (const XercesNodeImpl*)update.getTarget()->getInterface(Item::gXQilla); DOMAttr *domnode = (DOMAttr*)nodeImpl->getDOMNode(); Node::Ptr parentNode = nodeImpl->dmParent(context); DOMElement *element = domnode->getOwnerElement(); DOMDocument *doc = element->getOwnerDocument(); bool untyped = parentNode->dmNodeKind() == Node::element_string && XPath2Utils::equals(parentNode->getTypeName(), DocumentCache::g_szUntyped) && XPath2Utils::equals(parentNode->getTypeURI(), SchemaSymbols::fgURI_SCHEMAFORSCHEMA); Result children = update.getValue(); Item::Ptr item; while((item = children->next(context)).notNull()) { const XercesNodeImpl *childImpl = (const XercesNodeImpl*)item->getInterface(Item::gXQilla); DOMNode *newChild = importNodeFix(doc, const_cast<DOMNode*>(childImpl->getDOMNode()), /*deep*/true); // 1. Error checks: // a. If the QNames of any two attribute nodes in $replacement have implied namespace bindings that conflict with // each other, a dynamic error is raised [err:XUDY0024]. // b. If the QName of any attribute node in $replacement has an implied namespace binding that conflicts with a // namespace binding in the "namespaces" property of parent($target), a dynamic error is raised [err:XUDY0024]. // Checks performed by UpdateFactory // 2b. If the type-name property of parent($target) is xs:untyped, then upd:setToUntyped() is invoked // on each element node in $replacement. if(!untyped) setTypes(newChild, childImpl->getDOMNode()); // 2a. For each node in $replacement, the parent property is set to parent($target). // 4a. If $target is an attribute node, the attributes property of parent($target) is modified by removing $target // and adding the nodes in $replacement (if any). // 4b. If $target is an attribute node, the namespaces property of parent($target) is modified to include namespace // bindings for any attribute namespace prefixes in $replacement that did not already have bindings. element->setAttributeNode((DOMAttr*)newChild); } // 3a. $target is marked for deletion. forDeletion_.insert(domnode); // 4d. upd:removeType(parent($target)) is invoked. removeType(element); // Use parentNode, since the attr replace could have removed the original attr addToPutSet(parentNode, &update, context); }
void XercesUpdateFactory::applyInsertAfter(const PendingUpdate &update, DynamicContext *context) { const XercesNodeImpl *nodeImpl = (const XercesNodeImpl*)update.getTarget()->getInterface(Item::gXQilla); DOMNode *domnode = const_cast<DOMNode*>(nodeImpl->getDOMNode()); DOMNode *before = domnode->getNextSibling(); Node::Ptr parentNode = nodeImpl->dmParent(context); DOMNode *parent = domnode->getParentNode(); DOMDocument *doc = const_cast<DOMDocument*>(XPath2Utils::getOwnerDoc(domnode)); bool untyped = parentNode->dmNodeKind() == Node::element_string && XPath2Utils::equals(parentNode->getTypeName(), DocumentCache::g_szUntyped) && XPath2Utils::equals(parentNode->getTypeURI(), SchemaSymbols::fgURI_SCHEMAFORSCHEMA); bool containsElementOrText = false; Result children = update.getValue(); Item::Ptr item; while((item = children->next(context)).notNull()) { const XercesNodeImpl *childImpl = (const XercesNodeImpl*)item->getInterface(Item::gXQilla); DOMNode *newChild = importNodeFix(doc, const_cast<DOMNode*>(childImpl->getDOMNode()), /*deep*/true); if(childImpl->dmNodeKind() == Node::element_string || childImpl->dmNodeKind() == Node::text_string) { containsElementOrText = true; } // If the type-name property of parent($target) is xs:untyped, then upd:setToUntyped() is invoked on each // element or attribute node in $content. if(!untyped) setTypes(newChild, childImpl->getDOMNode()); // For each node in $content, the parent property is set to parent($target). // The children property of parent($target) is modified to add the nodes in $content just before $target, // preserving their order. parent->insertBefore(newChild, before); } // If at least one of the nodes in $content is an element or text node, upd:removeType(parent($target)) is invoked. if(containsElementOrText) { removeType(parent); } addToPutSet(update.getTarget(), &update, context); }
void XercesUpdateFactory::applyReplaceNode(const PendingUpdate &update, DynamicContext *context) { const XercesNodeImpl *nodeImpl = (const XercesNodeImpl*)update.getTarget()->getInterface(Item::gXQilla); DOMNode *domnode = const_cast<DOMNode*>(nodeImpl->getDOMNode()); Node::Ptr parentNode = nodeImpl->dmParent(context); DOMNode *parent = domnode->getParentNode(); DOMDocument *doc = const_cast<DOMDocument*>(XPath2Utils::getOwnerDoc(domnode)); bool untyped = parentNode->dmNodeKind() == Node::element_string && XPath2Utils::equals(parentNode->getTypeName(), DocumentCache::g_szUntyped) && XPath2Utils::equals(parentNode->getTypeURI(), SchemaSymbols::fgURI_SCHEMAFORSCHEMA); Result children = update.getValue(); Item::Ptr item; while((item = children->next(context)).notNull()) { const XercesNodeImpl *childImpl = (const XercesNodeImpl*)item->getInterface(Item::gXQilla); DOMNode *newChild = importNodeFix(doc, const_cast<DOMNode*>(childImpl->getDOMNode()), /*deep*/true); // 1b. If the type-name property of parent($target) is xs:untyped, then upd:setToUntyped() is invoked // on each element node in $replacement. if(!untyped) setTypes(newChild, childImpl->getDOMNode()); // 1a. For each node in $replacement, the parent property is set to parent($target). // 3b. If $target is an element, text, comment, or processing instruction node, the children property // of parent($target) is modified to add the nodes in $replacement just before $target, preserving // their order. parent->insertBefore(newChild, domnode); } // 2a. $target is marked for deletion. forDeletion_.insert(domnode); // 3c. upd:removeType(parent($target)) is invoked. removeType(parent); addToPutSet(update.getTarget(), &update, context); }
bool SequenceType::ItemType::matches(const Node::Ptr &toBeTested, DynamicContext* context) const { switch(m_nTestType) { case TEST_ELEMENT: { if(toBeTested->dmNodeKind() != Node::element_string) return false; if(!matchesNameType(toBeTested, context)) return false; // if the element has xsi:nil="true", m_bAllowNil MUST be true if(toBeTested->dmNilled(context)->isTrue() && !m_bAllowNil) return false; return true; } case TEST_ATTRIBUTE: { if(toBeTested->dmNodeKind() != Node::attribute_string) return false; if(!matchesNameType(toBeTested, context)) return false; return true; } case TEST_SCHEMA_ELEMENT: { if(toBeTested->dmNodeKind() != Node::element_string) return false; return matchesSchemaElement(toBeTested, context); } case TEST_SCHEMA_ATTRIBUTE: { if(toBeTested->dmNodeKind() != Node::attribute_string) return false; // retrieve the type of the attribute name assert(m_pName!=NULL); const XMLCh* attributeNS=m_NameURI; const XMLCh* attributeName=m_pName->getName(); SchemaAttDef* attrDecl=context->getDocumentCache()->getAttributeDecl(attributeNS, attributeName); assert(attrDecl != NULL); // 1. The name of the candidate node matches the specified AttributeName ATQNameOrDerived::Ptr name = toBeTested->dmNodeName(context); if(name.isNull()) return false; const XMLCh *node_uri = ((const ATQNameOrDerived*)name.get())->getURI(); const XMLCh *node_name = ((const ATQNameOrDerived*)name.get())->getName(); if(!(XPath2Utils::equals(attributeName, node_name)) || !(XPath2Utils::equals(attributeNS, node_uri))) return false; // 2. derives-from(AT, ET) is true, where AT is the type of the candidate node and ET is the type declared // for attribute AttributeName in the in-scope attribute declarations. DatatypeValidator* pDV=attrDecl->getDatatypeValidator(); if(pDV && !toBeTested->hasInstanceOfType(pDV->getTypeUri(), pDV->getTypeLocalName(), context)) return false; return true; } case TEST_PI: { if(toBeTested->dmNodeKind() != Node::processing_instruction_string) return false; if(!matchesNameType(toBeTested, context)) return false; return true; } case TEST_COMMENT: { return (toBeTested->dmNodeKind() == Node::comment_string); } case TEST_TEXT: { return (toBeTested->dmNodeKind() == Node::text_string); } case TEST_SCHEMA_DOCUMENT: case TEST_DOCUMENT: { if(toBeTested->dmNodeKind() != Node::document_string) return false; if(m_pName == NULL && m_pType == NULL) return true; // if we have a constraint on name/type, they apply to the document element Result children = toBeTested->dmChildren(context, 0); Node::Ptr docElement; while((docElement = children->next(context)).notNull() && docElement->dmNodeKind() != Node::element_string) {} if(docElement.isNull()) return false; if(m_nTestType == TEST_DOCUMENT) return matchesNameType(docElement, context); else return matchesSchemaElement(docElement, context); } case TEST_NODE: case TEST_ANYTHING: { return true; } case TEST_ATOMIC_TYPE: case TEST_FUNCTION: { return false; } } return true; }