// nsIExtendedExpatSink NS_IMETHODIMP nsSAXXMLReader::HandleStartElement(const PRUnichar *aName, const PRUnichar **aAtts, uint32_t aAttsCount, int32_t aIndex, uint32_t aLineNumber) { if (!mContentHandler) return NS_OK; nsCOMPtr<nsSAXAttributes> atts = new nsSAXAttributes(); if (!atts) return NS_ERROR_OUT_OF_MEMORY; nsAutoString uri, localName, qName; for (; *aAtts; aAtts += 2) { SplitExpatName(aAtts[0], uri, localName, qName); // XXX don't have attr type information NS_NAMED_LITERAL_STRING(cdataType, "CDATA"); // could support xmlns reporting, it's a standard SAX feature if (!uri.EqualsLiteral(XMLNS_URI)) { NS_ASSERTION(aAtts[1], "null passed to handler"); atts->AddAttribute(uri, localName, qName, cdataType, nsDependentString(aAtts[1])); } } // Deal with the element name SplitExpatName(aName, uri, localName, qName); return mContentHandler->StartElement(uri, localName, qName, atts); }
void RDFContentSinkImpl::SetParseMode(const PRUnichar **aAttributes) { nsCOMPtr<nsIAtom> localName; for (; *aAttributes; aAttributes += 2) { const nsDependentSubstring& nameSpaceURI = SplitExpatName(aAttributes[0], getter_AddRefs(localName)); if (localName == kParseTypeAtom) { nsDependentString v(aAttributes[1]); if (nameSpaceURI.IsEmpty() || nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI)) { if (v.EqualsLiteral("Resource")) mParseMode = eRDFContentSinkParseMode_Resource; break; } else if (nameSpaceURI.EqualsLiteral(NC_NAMESPACE_URI)) { if (v.EqualsLiteral("Date")) mParseMode = eRDFContentSinkParseMode_Date; else if (v.EqualsLiteral("Integer")) mParseMode = eRDFContentSinkParseMode_Int; break; } } } }
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 nsSAXXMLReader::HandleEndElement(const PRUnichar *aName) { if (mContentHandler) { nsAutoString uri, localName, qName; SplitExpatName(aName, uri, localName, qName); return mContentHandler->EndElement(uri, localName, qName); } return NS_OK; }
nsresult RDFContentSinkImpl::OpenMember(const PRUnichar* aName, const PRUnichar** aAttributes) { // ensure that we're actually reading a member element by making // sure that the opening tag is <rdf:li>, where "rdf:" corresponds // to whatever they've declared the standard RDF namespace to be. nsresult rv; nsCOMPtr<nsIAtom> localName; const nsDependentSubstring& nameSpaceURI = SplitExpatName(aName, getter_AddRefs(localName)); if (!nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI) || localName != kLiAtom) { PR_LOG(gLog, PR_LOG_ALWAYS, ("rdfxml: expected RDF:li at line %d", -1)); // XXX pass in line number return NS_ERROR_UNEXPECTED; } // The parent element is the container. nsIRDFResource* container = GetContextElement(0); if (! container) return NS_ERROR_NULL_POINTER; nsIRDFResource* resource; if (NS_SUCCEEDED(rv = GetResourceAttribute(aAttributes, &resource))) { // Okay, this node has an RDF:resource="..." attribute. That // means that it's a "referenced item," as covered in [6.29]. nsCOMPtr<nsIRDFContainer> c; NS_NewRDFContainer(getter_AddRefs(c)); c->Init(mDataSource, container); c->AppendElement(resource); // 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. NS_RELEASE(resource); } // Change state. Pushing a null context element is a bit weird, // but the idea is that there really is _no_ context "property". // The contained element will use nsIRDFContainer::AppendElement() to add // the element to the container, which requires only the container // and the element to be added. PushContext(nsnull, mState, mParseMode); mState = eRDFContentSinkState_InMemberElement; SetParseMode(aAttributes); return NS_OK; }
nsresult RDFContentSinkImpl::OpenRDF(const PRUnichar* aName) { // ensure that we're actually reading RDF by making sure that the // opening tag is <rdf:RDF>, where "rdf:" corresponds to whatever // they've declared the standard RDF namespace to be. nsCOMPtr<nsIAtom> localName; const nsDependentSubstring& nameSpaceURI = SplitExpatName(aName, getter_AddRefs(localName)); if (!nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI) || localName != kRDFAtom) { // PR_LOG(gLog, PR_LOG_ALWAYS, // ("rdfxml: expected RDF:RDF at line %d", // aNode.GetSourceLineNumber())); return NS_ERROR_UNEXPECTED; } PushContext(nsnull, mState, mParseMode); mState = eRDFContentSinkState_InDocumentElement; 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, PRBool* 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 = PR_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 = PR_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 = PR_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)); const char* attrName; localName->GetUTF8String(&attrName); NS_ConvertUTF16toUTF8 propertyStr(nameSpaceURI); propertyStr.Append(attrName); 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)); PRBool isAnonymous = PR_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, PR_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. PRBool isaTypedNode = PR_TRUE; if (nameSpaceURI.EqualsLiteral(RDF_NAMESPACE_URI)) { isaTypedNode = PR_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 = PR_TRUE; } } if (isaTypedNode) { const char* attrName; localName->GetUTF8String(&attrName); NS_ConvertUTF16toUTF8 typeStr(nameSpaceURI); typeStr.Append(attrName); nsCOMPtr<nsIRDFResource> type; nsresult rv = gRDFService->GetResource(typeStr, getter_AddRefs(type)); if (NS_FAILED(rv)) return rv; rv = mDataSource->Assert(source, kRDF_type, type, PR_TRUE); if (NS_FAILED(rv)) return rv; mState = eRDFContentSinkState_InDescriptionElement; } AddProperties(aAttributes, source); return NS_OK; }