PR_LOG(gXULTemplateLog, PR_LOG_ALWAYS,
PR_LOG(gLog, PR_LOG_ALWAYS,
nsXULTemplateBuilder::CompileTripleCondition(nsTemplateRule* aRule,                                             nsIContent* aCondition,                                             InnerNode* aParentNode,                                             TestNode** aResult){    // Compile a <triple> condition, which must be of the form:    //    //   <triple subject="?var1|resource"    //           predicate="resource"    //           object="?var2|resource|literal" />    //    // XXXwaterson Some day it would be cool to allow the 'predicate'    // to be bound to a variable.    // subject    nsAutoString subject;    aCondition->GetAttr(kNameSpaceID_None, nsXULAtoms::subject, subject);    PRInt32 svar = 0;    nsCOMPtr<nsIRDFResource> sres;    if (subject[0] == PRUnichar('?'))        svar = mRules.LookupSymbol(subject.get(), PR_TRUE);    else        gRDFService->GetUnicodeResource(subject, getter_AddRefs(sres));    // predicate    nsAutoString predicate;    aCondition->GetAttr(kNameSpaceID_None, nsXULAtoms::predicate, predicate);    nsCOMPtr<nsIRDFResource> pres;    if (predicate[0] == PRUnichar('?')) {        PR_LOG(gXULTemplateLog, PR_LOG_ALWAYS,               ("xultemplate[%p] cannot handle variables in <triple> 'predicate'", this));        return NS_OK;    }    else {        gRDFService->GetUnicodeResource(predicate, getter_AddRefs(pres));    }    // object    nsAutoString object;    aCondition->GetAttr(kNameSpaceID_None, nsXULAtoms::object, object);    PRInt32 ovar = 0;    nsCOMPtr<nsIRDFNode> onode;    if (object[0] == PRUnichar('?')) {        ovar = mRules.LookupSymbol(object.get(), PR_TRUE);    }    else if (object.FindChar(':') != -1) { // XXXwaterson evil.        // treat as resource        nsCOMPtr<nsIRDFResource> resource;        gRDFService->GetUnicodeResource(object, getter_AddRefs(resource));        onode = do_QueryInterface(resource);    }    else {        nsAutoString parseType;        aCondition->GetAttr(kNameSpaceID_None, nsXULAtoms::parsetype, parseType);        nsresult rv = ParseLiteral(parseType, object, getter_AddRefs(onode));        if (NS_FAILED(rv))            return rv;    }    nsRDFPropertyTestNode* testnode = nsnull;    if (svar && ovar) {        testnode = new nsRDFPropertyTestNode(aParentNode, mConflictSet, mDB, svar, pres, ovar);    }    else if (svar) {        testnode = new nsRDFPropertyTestNode(aParentNode, mConflictSet, mDB, svar, pres, onode);    }    else if (ovar) {        testnode = new nsRDFPropertyTestNode(aParentNode, mConflictSet, mDB, sres, pres, ovar);    }    else {        PR_LOG(gXULTemplateLog, PR_LOG_ALWAYS,               ("xultemplate[%p] tautology in <triple> test", this));        return NS_OK;    }    if (! testnode)        return NS_ERROR_OUT_OF_MEMORY;    mRDFTests.Add(testnode);    *aResult = testnode;    return NS_OK;}