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; }
nsresult RDFContentSinkImpl::GetResourceAttribute(const PRUnichar** aAttributes, nsIRDFResource** aResource) { nsCOMPtr<nsIAtom> localName; nsAutoString nodeID; for (; *aAttributes; aAttributes += 2) { const nsDependentSubstring& nameSpaceURI = SplitExpatName(aAttributes[0], getter_AddRefs(localName)); // We'll accept `resource' or `rdf:resource', under the spirit // that we should be liberal towards the input that we // receive. if (!nameSpaceURI.IsEmpty() && !nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI)) { continue; } // XXX you can't specify both, but we'll just pick up the // first thing that was specified and ignore the other. if (localName == kResourceAtom) { // XXX Take the URI and make it fully qualified by // sticking it into the document's URL. This may not be // appropriate... nsAutoString relURI(aAttributes[1]); if (rdf_RequiresAbsoluteURI(relURI)) { nsresult rv; nsCAutoString uri; rv = mDocumentURL->Resolve(NS_ConvertUTF16toUTF8(aAttributes[1]), uri); if (NS_FAILED(rv)) return rv; return gRDFService->GetResource(uri, aResource); } return gRDFService->GetResource(NS_ConvertUTF16toUTF8(aAttributes[1]), aResource); } else if (localName == kNodeIdAtom) { nodeID.Assign(aAttributes[1]); } } // If nodeID is present, check if we already know about it. If we've seen // the nodeID before, use the same resource, otherwise generate a new one. if (!nodeID.IsEmpty()) { mNodeIDMap.Get(nodeID,aResource); if (!*aResource) { nsresult rv; rv = gRDFService->GetAnonymousResource(aResource); if (NS_FAILED(rv)) { return rv; } mNodeIDMap.Put(nodeID,*aResource); } return NS_OK; } return NS_ERROR_FAILURE; }
nsresult RDFContentSinkImpl::GetIdAboutAttribute(const PRUnichar** aAttributes, nsIRDFResource** aResource, bool* aIsAnonymous) { // This corresponds to the dirty work of production [6.5] nsresult rv = NS_OK; nsAutoString nodeID; nsCOMPtr<nsIAtom> localName; for (; *aAttributes; aAttributes += 2) { const nsDependentSubstring& nameSpaceURI = SplitExpatName(aAttributes[0], getter_AddRefs(localName)); // We'll accept either `ID' or `rdf:ID' (ibid with `about' or // `rdf:about') in the spirit of being liberal towards the // input that we receive. if (!nameSpaceURI.IsEmpty() && !nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI)) { continue; } // XXX you can't specify both, but we'll just pick up the // first thing that was specified and ignore the other. if (localName == kAboutAtom) { if (aIsAnonymous) *aIsAnonymous = false; nsAutoString relURI(aAttributes[1]); if (rdf_RequiresAbsoluteURI(relURI)) { nsCAutoString uri; rv = mDocumentURL->Resolve(NS_ConvertUTF16toUTF8(aAttributes[1]), uri); if (NS_FAILED(rv)) return rv; return gRDFService->GetResource(uri, aResource); } return gRDFService->GetResource(NS_ConvertUTF16toUTF8(aAttributes[1]), aResource); } else if (localName == kIdAtom) { if (aIsAnonymous) *aIsAnonymous = false; // In the spirit of leniency, we do not bother trying to // enforce that this be a valid "XML Name" (see // http://www.w3.org/TR/REC-xml#NT-Nmtoken), as per // 6.21. If we wanted to, this would be where to do it. // Construct an in-line resource whose URI is the // document's URI plus the XML name specified in the ID // attribute. nsCAutoString name; nsCAutoString ref('#'); AppendUTF16toUTF8(aAttributes[1], ref); rv = mDocumentURL->Resolve(ref, name); if (NS_FAILED(rv)) return rv; return gRDFService->GetResource(name, aResource); } else if (localName == kNodeIdAtom) { nodeID.Assign(aAttributes[1]); } else if (localName == kAboutEachAtom) { // XXX we don't deal with aboutEach... //PR_LOG(gLog, PR_LOG_WARNING, // ("rdfxml: ignoring aboutEach at line %d", // aNode.GetSourceLineNumber())); } } // Otherwise, we couldn't find anything, so just gensym one... if (aIsAnonymous) *aIsAnonymous = true; // If nodeID is present, check if we already know about it. If we've seen // the nodeID before, use the same resource, otherwise generate a new one. if (!nodeID.IsEmpty()) { mNodeIDMap.Get(nodeID,aResource); if (!*aResource) { rv = gRDFService->GetAnonymousResource(aResource); mNodeIDMap.Put(nodeID,*aResource); } } else { rv = gRDFService->GetAnonymousResource(aResource); } 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; }