Example #1
0
// 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;
}
Example #4
0
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;
}