nsresult RDFContentSinkImpl::ReinitContainer(nsIRDFResource* aContainerType, nsIRDFResource* aContainer) { // Mega-kludge to deal with the fact that Make[Seq|Alt|Bag] is // idempotent, and as such, containers will have state (e.g., // RDF:nextVal) maintained in the graph across loads. This // re-initializes each container's RDF:nextVal to '1', and 'marks' // the container as such. nsresult rv; nsCOMPtr<nsIRDFLiteral> one; rv = gRDFService->GetLiteral(NS_LITERAL_STRING("1").get(), getter_AddRefs(one)); if (NS_FAILED(rv)) return rv; // Re-initialize the 'nextval' property nsCOMPtr<nsIRDFNode> nextval; rv = mDataSource->GetTarget(aContainer, kRDF_nextVal, true, getter_AddRefs(nextval)); if (NS_FAILED(rv)) return rv; rv = mDataSource->Change(aContainer, kRDF_nextVal, nextval, one); if (NS_FAILED(rv)) return rv; // Re-mark as a container. XXX should be kRDF_type rv = mDataSource->Assert(aContainer, kRDF_instanceOf, aContainerType, true); NS_ASSERTION(NS_SUCCEEDED(rv), "unable to mark container as such"); if (NS_FAILED(rv)) return rv; return NS_OK; }
nsresult RDFContentSinkImpl::AddProperties(const PRUnichar** aAttributes, nsIRDFResource* aSubject, PRInt32* aCount) { if (aCount) *aCount = 0; nsCOMPtr<nsIAtom> localName; for (; *aAttributes; aAttributes += 2) { const nsDependentSubstring& nameSpaceURI = SplitExpatName(aAttributes[0], getter_AddRefs(localName)); // skip 'xmlns' directives, these are "meta" information if (nameSpaceURI.EqualsLiteral("http://www.w3.org/2000/xmlns/")) { continue; } // skip `about', `ID', `resource', and 'nodeID' attributes (either with or // without the `rdf:' prefix); these are all "special" and // should've been dealt with by the caller. if (localName == kAboutAtom || localName == kIdAtom || localName == kResourceAtom || localName == kNodeIdAtom) { if (nameSpaceURI.IsEmpty() || nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI)) continue; } // Skip `parseType', `RDF:parseType', and `NC:parseType'. This // is meta-information that will be handled in SetParseMode. if (localName == kParseTypeAtom) { if (nameSpaceURI.IsEmpty() || nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI) || nameSpaceURI.EqualsLiteral(NC_NAMESPACE_URI)) { continue; } } const char* attrName; localName->GetUTF8String(&attrName); NS_ConvertUTF16toUTF8 propertyStr(nameSpaceURI); propertyStr.Append(attrName); // Add the assertion to RDF nsCOMPtr<nsIRDFResource> property; gRDFService->GetResource(propertyStr, getter_AddRefs(property)); nsCOMPtr<nsIRDFLiteral> target; gRDFService->GetLiteral(aAttributes[1], getter_AddRefs(target)); mDataSource->Assert(aSubject, property, target, PR_TRUE); } return NS_OK; }
NS_IMETHODIMP RDFContentSinkImpl::HandleEndElement(const PRUnichar *aName) { FlushText(); nsIRDFResource* resource; if (NS_FAILED(PopContext(resource, mState, mParseMode))) { // XXX parser didn't catch unmatched tags? #ifdef PR_LOGGING if (PR_LOG_TEST(gLog, PR_LOG_WARNING)) { nsAutoString tagStr(aName); char* tagCStr = ToNewCString(tagStr); PR_LogPrint ("rdfxml: extra close tag '%s' at line %d", tagCStr, 0/*XXX fix me */); NS_Free(tagCStr); } #endif return NS_ERROR_UNEXPECTED; // XXX } // If we've just popped a member or property element, _now_ is the // time to add that element to the graph. switch (mState) { case eRDFContentSinkState_InMemberElement: { nsCOMPtr<nsIRDFContainer> container; NS_NewRDFContainer(getter_AddRefs(container)); container->Init(mDataSource, GetContextElement(1)); container->AppendElement(resource); } break; case eRDFContentSinkState_InPropertyElement: { mDataSource->Assert(GetContextElement(1), GetContextElement(0), resource, true); } break; default: break; } if (mContextStack->IsEmpty()) mState = eRDFContentSinkState_InEpilog; NS_IF_RELEASE(resource); return NS_OK; }
nsresult RDFContentSinkImpl::FlushText() { nsresult rv = NS_OK; if (0 != mTextLength) { if (rdf_IsDataInBuffer(mText, mTextLength)) { // XXX if there's anything but whitespace, then we'll // create a text node. switch (mState) { case eRDFContentSinkState_InMemberElement: { nsCOMPtr<nsIRDFNode> node; ParseText(getter_AddRefs(node)); nsCOMPtr<nsIRDFContainer> container; NS_NewRDFContainer(getter_AddRefs(container)); container->Init(mDataSource, GetContextElement(1)); container->AppendElement(node); } break; case eRDFContentSinkState_InPropertyElement: { nsCOMPtr<nsIRDFNode> node; ParseText(getter_AddRefs(node)); mDataSource->Assert(GetContextElement(1), GetContextElement(0), node, true); } break; default: // just ignore it break; } } mTextLength = 0; } return rv; }
nsresult RDFContentSinkImpl::OpenProperty(const PRUnichar* aName, const PRUnichar** aAttributes) { nsresult rv; // an "object" non-terminal is either a "description", a "typed // node", or a "container", so this change the content sink's // state appropriately. nsCOMPtr<nsIAtom> localName; const nsDependentSubstring& nameSpaceURI = SplitExpatName(aName, getter_AddRefs(localName)); NS_ConvertUTF16toUTF8 propertyStr(nameSpaceURI); propertyStr.Append(nsAtomCString(localName)); nsCOMPtr<nsIRDFResource> property; rv = gRDFService->GetResource(propertyStr, getter_AddRefs(property)); if (NS_FAILED(rv)) return rv; // See if they've specified a 'resource' attribute, in which case // they mean *that* to be the object of this property. nsCOMPtr<nsIRDFResource> target; GetResourceAttribute(aAttributes, getter_AddRefs(target)); bool isAnonymous = false; if (! target) { // See if an 'ID' attribute has been specified, in which case // this corresponds to the fourth form of [6.12]. // XXX strictly speaking, we should reject the RDF/XML as // invalid if they've specified both an 'ID' and a 'resource' // attribute. Bah. // XXX strictly speaking, 'about=' isn't allowed here, but // what the hell. GetIdAboutAttribute(aAttributes, getter_AddRefs(target), &isAnonymous); } if (target) { // They specified an inline resource for the value of this // property. Create an RDF resource for the inline resource // URI, add the properties to it, and attach the inline // resource to its parent. PRInt32 count; rv = AddProperties(aAttributes, target, &count); NS_ASSERTION(NS_SUCCEEDED(rv), "problem adding properties"); if (NS_FAILED(rv)) return rv; if (count || !isAnonymous) { // If the resource was "anonymous" (i.e., they hadn't // explicitly set an ID or resource attribute), then we'll // only assert this property from the context element *if* // there were properties specified on the anonymous // resource. rv = mDataSource->Assert(GetContextElement(0), property, target, true); if (NS_FAILED(rv)) return rv; } // XXX Technically, we should _not_ fall through here and push // the element onto the stack: this is supposed to be a closed // node. But right now I'm lazy and the code will just Do The // Right Thing so long as the RDF is well-formed. } // Push the element onto the context stack and change state. PushContext(property, mState, mParseMode); mState = eRDFContentSinkState_InPropertyElement; SetParseMode(aAttributes); return NS_OK; }
nsresult RDFContentSinkImpl::OpenObject(const PRUnichar* aName, const PRUnichar** aAttributes) { // an "object" non-terminal is either a "description", a "typed // node", or a "container", so this change the content sink's // state appropriately. nsCOMPtr<nsIAtom> localName; const nsDependentSubstring& nameSpaceURI = SplitExpatName(aName, getter_AddRefs(localName)); // Figure out the URI of this object, and create an RDF node for it. nsCOMPtr<nsIRDFResource> source; GetIdAboutAttribute(aAttributes, getter_AddRefs(source)); // If there is no `ID' or `about', then there's not much we can do. if (! source) return NS_ERROR_FAILURE; // Push the element onto the context stack PushContext(source, mState, mParseMode); // Now figure out what kind of state transition we need to // make. We'll either be going into a mode where we parse a // description or a container. bool isaTypedNode = true; if (nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI)) { isaTypedNode = false; if (localName == kDescriptionAtom) { // it's a description mState = eRDFContentSinkState_InDescriptionElement; } else if (localName == kBagAtom) { // it's a bag container InitContainer(kRDF_Bag, source); mState = eRDFContentSinkState_InContainerElement; } else if (localName == kSeqAtom) { // it's a seq container InitContainer(kRDF_Seq, source); mState = eRDFContentSinkState_InContainerElement; } else if (localName == kAltAtom) { // it's an alt container InitContainer(kRDF_Alt, source); mState = eRDFContentSinkState_InContainerElement; } else { // heh, that's not *in* the RDF namespace: just treat it // like a typed node isaTypedNode = true; } } if (isaTypedNode) { NS_ConvertUTF16toUTF8 typeStr(nameSpaceURI); typeStr.Append(nsAtomCString(localName)); nsCOMPtr<nsIRDFResource> type; nsresult rv = gRDFService->GetResource(typeStr, getter_AddRefs(type)); if (NS_FAILED(rv)) return rv; rv = mDataSource->Assert(source, kRDF_type, type, true); if (NS_FAILED(rv)) return rv; mState = eRDFContentSinkState_InDescriptionElement; } AddProperties(aAttributes, source); return NS_OK; }