diff --git a/rdf/base/idl/Makefile.in b/rdf/base/idl/Makefile.in index f9c9cc8ec91d..ad44db15a692 100644 --- a/rdf/base/idl/Makefile.in +++ b/rdf/base/idl/Makefile.in @@ -46,6 +46,9 @@ MODULE = rdf GRE_MODULE = 1 XPIDLSRCS = \ + rdfIDataSource.idl \ + rdfITripleVisitor.idl \ + rdfISerializer.idl \ nsIRDFCompositeDataSource.idl \ nsIRDFContainer.idl \ nsIRDFContainerUtils.idl \ diff --git a/rdf/base/idl/rdfIDataSource.idl b/rdf/base/idl/rdfIDataSource.idl new file mode 100644 index 000000000000..78fff59764dd --- /dev/null +++ b/rdf/base/idl/rdfIDataSource.idl @@ -0,0 +1,71 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg . + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Axel Hecht + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +interface rdfITripleVisitor; + +/** + * Interface used in RDF to describe data sources. + * + * @status PLASMA + */ + +[scriptable, uuid(ebce86bd-1568-4a34-a808-9ccf9cde8087)] +interface rdfIDataSource : nsISupports +{ + /** + * Visit all the subject resources in the datasource. The order is + * intederminate and may change from one invocation to the next. + * The subjects will be in the aSubject argument in calls into + * aVisitor, aPredicate and aObject will be null. + * @note Implementations may throw NS_ERROR_NOT_IMPLEMENTED for + * this method, but in this case RDF serializations of this + * datasource will not be possible. + */ + void visitAllSubjects(in rdfITripleVisitor aVisitor); + + /** + * Visit all the triples in the datasource. The order is + * intederminate and may change from one invocation to the next. + * @note Implementations may throw NS_ERROR_NOT_IMPLEMENTED for + * this method, but in this case RDF serializations of this + * datasource will not be possible. + */ + void visitAllTriples(in rdfITripleVisitor aVisitor); +}; diff --git a/rdf/base/idl/rdfISerializer.idl b/rdf/base/idl/rdfISerializer.idl new file mode 100644 index 000000000000..a4fc6e65f450 --- /dev/null +++ b/rdf/base/idl/rdfISerializer.idl @@ -0,0 +1,63 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is + * Axel Hecht . + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Axel Hecht + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +interface rdfIDataSource; +interface nsIOutputStream; + +/** + * Interface used to serialize RDF. + * + * @status PLASMA + */ + +[scriptable, uuid(f0edfcdd-8bca-4d32-9226-7421001396a4)] +interface rdfISerializer : nsISupports +{ + /** + * Synchronously serialize the given datasource to the outputstream. + * + * Implementations are not required to implement any buffering or + * other stream-based optimizations. + * + * @param aDataSource The RDF data source to be serialized. + * @param aOut The output stream to use. + */ + void serialize(in rdfIDataSource aDataSource, in nsIOutputStream aOut); +}; diff --git a/rdf/base/idl/rdfITripleVisitor.idl b/rdf/base/idl/rdfITripleVisitor.idl new file mode 100644 index 000000000000..dd03f729ac81 --- /dev/null +++ b/rdf/base/idl/rdfITripleVisitor.idl @@ -0,0 +1,64 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is + * Benjamin Smedberg . + * Portions created by the Initial Developer are Copyright (C) 2004 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Axel Hecht + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsISupports.idl" + +interface nsIRDFResource; +interface nsIRDFNode; + +/** + * Interface used in RDF to enumerate triples. + * Also used by rdfIDataSource::getAllSubjects, then aPredicate, + * aObject and aTruthValue are ignored. + * + * @status PLASMA + */ + +[scriptable, function, uuid(aafea151-c271-4505-9978-a100d292800c)] +interface rdfITripleVisitor : nsISupports +{ + /** + * Callback function for returning query results. + * + * @param aSubject, aPredicate, aObject describe the (sub-)arc + * @returnCode NS_RDF_STOP_VISIT to stop iterating over the query result. + * Any error code will stop the iteration as well. + */ + void visit(in nsIRDFNode aSubject, in nsIRDFResource aPredicate, + in nsIRDFNode aObject, in boolean aTruthValue); +}; diff --git a/rdf/base/public/rdf.h b/rdf/base/public/rdf.h index 9fa3345d25fa..4c0e04258789 100644 --- a/rdf/base/public/rdf.h +++ b/rdf/base/public/rdf.h @@ -95,6 +95,9 @@ static const char kURI##prefix##_##name[] = ns #name willing to record the statement. */ #define NS_RDF_ASSERTION_REJECTED NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_RDF, 3) +/* Return this from rdfITripleVisitor to stop cycling */ +#define NS_RDF_STOP_VISIT NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_RDF, 4) + /* ContractID prefixes for RDF DLL registration. */ @@ -105,6 +108,8 @@ static const char kURI##prefix##_##name[] = ns #name #define NS_RDF_RESOURCE_FACTORY_CONTRACTID_PREFIX NS_RDF_RESOURCE_FACTORY_CONTRACTID "?name=" #define NS_RDF_INFER_DATASOURCE_CONTRACTID_PREFIX NS_RDF_CONTRACTID "/infer-datasource;1?engine=" +#define NS_RDF_SERIALIZER NS_RDF_CONTRACTID "/serializer;1?format=" + // contract ID is in the form // @mozilla.org/rdf/delegate-factory;1?key=&scheme= #define NS_RDF_DELEGATEFACTORY_CONTRACTID "@mozilla.org/rdf/delegate-factory;1" diff --git a/rdf/base/src/Makefile.in b/rdf/base/src/Makefile.in index 85671935bb7c..3ceacdee2136 100644 --- a/rdf/base/src/Makefile.in +++ b/rdf/base/src/Makefile.in @@ -56,6 +56,7 @@ REQUIRES = xpcom \ $(NULL) CPPSRCS = \ + rdfTriplesSerializer.cpp \ nsCompositeDataSource.cpp \ nsContainerEnumerator.cpp \ nsDefaultResourceFactory.cpp \ diff --git a/rdf/base/src/nsInMemoryDataSource.cpp b/rdf/base/src/nsInMemoryDataSource.cpp index 1932768d167c..831a04964990 100644 --- a/rdf/base/src/nsInMemoryDataSource.cpp +++ b/rdf/base/src/nsInMemoryDataSource.cpp @@ -99,6 +99,8 @@ #include "prlog.h" #include "rdf.h" +#include "rdfIDataSource.h" +#include "rdfITripleVisitor.h" #ifdef PR_LOGGING static PRLogModuleInfo* gLog = nsnull; @@ -293,7 +295,8 @@ class InMemoryResourceEnumeratorImpl; class InMemoryDataSource : public nsIRDFDataSource, public nsIRDFInMemoryDataSource, public nsIRDFPropagatableDataSource, - public nsIRDFPurgeableDataSource + public nsIRDFPurgeableDataSource, + public rdfIDataSource { protected: nsFixedSizeAllocator mAllocator; @@ -309,6 +312,10 @@ protected: nsCOMArray mObservers; PRUint32 mNumObservers; + // VisitFoo needs to block writes, [Un]Assert only allowed + // during mReadCount == 0 + PRUint32 mReadCount; + static PLDHashOperator PR_CALLBACK DeleteForwardArcsEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr, PRUint32 aNumber, void* aArg); @@ -355,6 +362,9 @@ public: // nsIRDFPurgeableDataSource methods NS_DECL_NSIRDFPURGEABLEDATASOURCE + // rdfIDataSource methods + NS_DECL_RDFIDATASOURCE + protected: static PLDHashOperator PR_CALLBACK SweepForwardArcsEntries(PLDHashTable* aTable, PLDHashEntryHdr* aHdr, @@ -867,7 +877,7 @@ NS_NewRDFInMemoryDataSource(nsISupports* aOuter, const nsIID& aIID, void** aResu InMemoryDataSource::InMemoryDataSource(nsISupports* aOuter) - : mNumObservers(0) + : mNumObservers(0), mReadCount(0) { NS_INIT_AGGREGATED(aOuter); @@ -988,6 +998,9 @@ InMemoryDataSource::AggregatedQueryInterface(REFNSIID aIID, void** aResult) else if (aIID.Equals(NS_GET_IID(nsIRDFPurgeableDataSource))) { *aResult = NS_STATIC_CAST(nsIRDFPurgeableDataSource*, this); } + else if (aIID.Equals(NS_GET_IID(rdfIDataSource))) { + *aResult = NS_STATIC_CAST(rdfIDataSource*, this); + } else { *aResult = nsnull; return NS_NOINTERFACE; @@ -1373,6 +1386,11 @@ InMemoryDataSource::Assert(nsIRDFResource* aSource, if (! aTarget) return NS_ERROR_NULL_POINTER; + if (mReadCount) { + NS_WARNING("Writing to InMemoryDataSource during read\n"); + return NS_RDF_ASSERTION_REJECTED; + } + nsresult rv; rv = LockedAssert(aSource, aProperty, aTarget, aTruthValue); if (NS_FAILED(rv)) return rv; @@ -1527,6 +1545,11 @@ InMemoryDataSource::Unassert(nsIRDFResource* aSource, if (! aTarget) return NS_ERROR_NULL_POINTER; + if (mReadCount) { + NS_WARNING("Writing to InMemoryDataSource during read\n"); + return NS_RDF_ASSERTION_REJECTED; + } + nsresult rv; rv = LockedUnassert(aSource, aProperty, aTarget); @@ -1571,6 +1594,11 @@ InMemoryDataSource::Change(nsIRDFResource* aSource, if (! aNewTarget) return NS_ERROR_NULL_POINTER; + if (mReadCount) { + NS_WARNING("Writing to InMemoryDataSource during read\n"); + return NS_RDF_ASSERTION_REJECTED; + } + nsresult rv; // XXX We can implement LockedChange() if we decide that this @@ -1621,6 +1649,11 @@ InMemoryDataSource::Move(nsIRDFResource* aOldSource, if (! aTarget) return NS_ERROR_NULL_POINTER; + if (mReadCount) { + NS_WARNING("Writing to InMemoryDataSource during read\n"); + return NS_RDF_ASSERTION_REJECTED; + } + nsresult rv; // XXX We can implement LockedMove() if we decide that this @@ -2117,4 +2150,130 @@ InMemoryDataSource::SweepForwardArcsEntries(PLDHashTable* aTable, } //////////////////////////////////////////////////////////////////////// +// rdfIDataSource methods + +class VisitorClosure +{ +public: + VisitorClosure(rdfITripleVisitor* aVisitor) : + mVisitor(aVisitor), + mRv(NS_OK) + {}; + rdfITripleVisitor* mVisitor; + nsresult mRv; +}; + +PLDHashOperator PR_CALLBACK +SubjectEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr, + PRUint32 aNumber, void* aArg) { + Entry* entry = NS_REINTERPRET_CAST(Entry*, aHdr); + VisitorClosure* closure = NS_STATIC_CAST(VisitorClosure*, aArg); + + nsresult rv; + nsCOMPtr subject = do_QueryInterface(entry->mNode, &rv); + NS_ENSURE_SUCCESS(rv, PL_DHASH_NEXT); + + closure->mRv = closure->mVisitor->Visit(subject, nsnull, nsnull, PR_TRUE); + if (NS_FAILED(closure->mRv) || closure->mRv == NS_RDF_STOP_VISIT) + return PL_DHASH_STOP; + + return PL_DHASH_NEXT; +} + +NS_IMETHODIMP +InMemoryDataSource::VisitAllSubjects(rdfITripleVisitor *aVisitor) +{ + // Lock datasource against writes + ++mReadCount; + + // Enumerate all of our entries into an nsISupportsArray. + VisitorClosure cls(aVisitor); + PL_DHashTableEnumerate(&mForwardArcs, SubjectEnumerator, &cls); + + // Unlock datasource + --mReadCount; + + return cls.mRv; +} + +class TriplesInnerClosure +{ +public: + TriplesInnerClosure(nsIRDFNode* aSubject, VisitorClosure* aClosure) : + mSubject(aSubject), mOuter(aClosure) {}; + nsIRDFNode* mSubject; + VisitorClosure* mOuter; +}; + +PLDHashOperator PR_CALLBACK +TriplesInnerEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr, + PRUint32 aNumber, void* aArg) { + Entry* entry = NS_REINTERPRET_CAST(Entry*, aHdr); + Assertion* assertion = entry->mAssertions; + TriplesInnerClosure* closure = + NS_STATIC_CAST(TriplesInnerClosure*, aArg); + while (assertion) { + NS_ASSERTION(!assertion->mHashEntry, "shouldn't have to hashes"); + VisitorClosure* cls = closure->mOuter; + cls->mRv = cls->mVisitor->Visit(closure->mSubject, + assertion->u.as.mProperty, + assertion->u.as.mTarget, + assertion->u.as.mTruthValue); + if (NS_FAILED(cls->mRv) || cls->mRv == NS_RDF_STOP_VISIT) { + return PL_DHASH_STOP; + } + assertion = assertion->mNext; + } + return PL_DHASH_NEXT; +} +PLDHashOperator PR_CALLBACK +TriplesEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr, + PRUint32 aNumber, void* aArg) { + Entry* entry = NS_REINTERPRET_CAST(Entry*, aHdr); + VisitorClosure* closure = NS_STATIC_CAST(VisitorClosure*, aArg); + + nsresult rv; + nsCOMPtr subject = do_QueryInterface(entry->mNode, &rv); + NS_ENSURE_SUCCESS(rv, PL_DHASH_NEXT); + + if (entry->mAssertions->mHashEntry) { + TriplesInnerClosure cls(subject, closure); + PL_DHashTableEnumerate(entry->mAssertions->u.hash.mPropertyHash, + TriplesInnerEnumerator, &cls); + if (NS_FAILED(closure->mRv)) { + return PL_DHASH_STOP; + } + return PL_DHASH_NEXT; + } + Assertion* assertion = entry->mAssertions; + while (assertion) { + NS_ASSERTION(!assertion->mHashEntry, "shouldn't have to hashes"); + closure->mRv = closure->mVisitor->Visit(subject, + assertion->u.as.mProperty, + assertion->u.as.mTarget, + assertion->u.as.mTruthValue); + if (NS_FAILED(closure->mRv) || closure->mRv == NS_RDF_STOP_VISIT) { + return PL_DHASH_STOP; + } + assertion = assertion->mNext; + } + return PL_DHASH_NEXT; +} +NS_IMETHODIMP +InMemoryDataSource::VisitAllTriples(rdfITripleVisitor *aVisitor) +{ + // Lock datasource against writes + ++mReadCount; + + // Enumerate all of our entries into an nsISupportsArray. + VisitorClosure cls(aVisitor); + PL_DHashTableEnumerate(&mForwardArcs, TriplesEnumerator, &cls); + + // Unlock datasource + --mReadCount; + + return cls.mRv; +} + +//////////////////////////////////////////////////////////////////////// diff --git a/rdf/base/src/nsRDFXMLDataSource.cpp b/rdf/base/src/nsRDFXMLDataSource.cpp index 14a1950718ec..2e09129b7bd6 100644 --- a/rdf/base/src/nsRDFXMLDataSource.cpp +++ b/rdf/base/src/nsRDFXMLDataSource.cpp @@ -123,6 +123,8 @@ #include "nsNameSpaceMap.h" #include "nsCRT.h" +#include "rdfIDataSource.h" + //---------------------------------------------------------------------- static NS_DEFINE_CID(kRDFInMemoryDataSourceCID, NS_RDFINMEMORYDATASOURCE_CID); @@ -215,7 +217,8 @@ class RDFXMLDataSourceImpl : public nsIRDFDataSource, public nsIRDFRemoteDataSource, public nsIRDFXMLSink, public nsIRDFXMLSource, - public nsIStreamListener + public nsIStreamListener, + public rdfIDataSource { protected: enum LoadState { @@ -386,6 +389,21 @@ public: // nsIStreamListener NS_DECL_NSISTREAMLISTENER + // rdfIDataSource + NS_IMETHOD VisitAllSubjects(rdfITripleVisitor *aVisitor) { + nsresult rv; + nsCOMPtr rdfds = do_QueryInterface(mInner, &rv); + if (NS_FAILED(rv)) return rv; + return rdfds->VisitAllSubjects(aVisitor); + } + + NS_IMETHOD VisitAllTriples(rdfITripleVisitor *aVisitor) { + nsresult rv; + nsCOMPtr rdfds = do_QueryInterface(mInner, &rv); + if (NS_FAILED(rv)) return rv; + return rdfds->VisitAllTriples(aVisitor); + } + // Implementation methods PRBool MakeQName(nsIRDFResource* aResource, @@ -519,13 +537,14 @@ RDFXMLDataSourceImpl::~RDFXMLDataSourceImpl(void) } -NS_IMPL_ISUPPORTS6(RDFXMLDataSourceImpl, +NS_IMPL_ISUPPORTS7(RDFXMLDataSourceImpl, nsIRDFDataSource, nsIRDFRemoteDataSource, nsIRDFXMLSink, nsIRDFXMLSource, nsIRequestObserver, - nsIStreamListener) + nsIStreamListener, + rdfIDataSource) nsresult diff --git a/rdf/base/src/nsRDFXMLSerializer.cpp b/rdf/base/src/nsRDFXMLSerializer.cpp index d619462e2775..14f8b1f7a2c7 100644 --- a/rdf/base/src/nsRDFXMLSerializer.cpp +++ b/rdf/base/src/nsRDFXMLSerializer.cpp @@ -22,6 +22,7 @@ * * Contributor(s): * Chris Waterson + * Axel Hecht * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), @@ -50,6 +51,10 @@ #include "rdf.h" #include "rdfutil.h" +#include "rdfIDataSource.h" + +#include "nsITimelineService.h" + PRInt32 nsRDFXMLSerializer::gRefCnt = 0; nsIRDFContainerUtils* nsRDFXMLSerializer::gRDFC; nsIRDFResource* nsRDFXMLSerializer::kRDF_instanceOf; @@ -161,13 +166,25 @@ nsRDFXMLSerializer::Init(nsIRDFDataSource* aDataSource) prefix = do_GetAtom("NC"); AddNameSpace(prefix, NS_LITERAL_STRING("http://home.netscape.com/NC-rdf#")); + mQNames.Init(); + mPrefixID = 0; + return NS_OK; } NS_IMETHODIMP nsRDFXMLSerializer::AddNameSpace(nsIAtom* aPrefix, const nsAString& aURI) { - mNameSpaces.Put(aURI, aPrefix); + nsCOMPtr prefix = aPrefix; + if (!prefix) { + // Make up a prefix, we don't want default namespaces, so + // that we can use QNames for elements and attributes alike. + nsCAutoString pref; + pref.AssignLiteral("NS"); + pref.AppendInt(++mPrefixID, 10); + prefix = do_GetAtom(pref); + } + mNameSpaces.Put(aURI, prefix); return NS_OK; } @@ -203,31 +220,24 @@ rdf_BlockingWrite(nsIOutputStream* stream, const nsAString& s) } // This converts a property resource (like -// "http://www.w3.org/TR/WD-rdf-syntax#Description") into a property -// ("Description"), a namespace prefix ("RDF"), and a namespace URI -// ("http://www.w3.org/TR/WD-rdf-syntax#"). +// "http://www.w3.org/TR/WD-rdf-syntax#Description") into a QName +// ("RDF:Description"), and registers the namespace, if it's made up. -PRBool -nsRDFXMLSerializer::MakeQName(nsIRDFResource* aResource, - nsCString& aProperty, - nsCString& aNameSpacePrefix, - nsCString& aNameSpaceURI) +nsresult +nsRDFXMLSerializer::RegisterQName(nsIRDFResource* aResource) { - nsCAutoString uri; + nsCAutoString uri, qname; aResource->GetValueUTF8(uri); nsNameSpaceMap::const_iterator iter = mNameSpaces.GetNameSpaceOf(uri); if (iter != mNameSpaces.last()) { - if (iter->mPrefix) - iter->mPrefix->ToUTF8String(aNameSpacePrefix); - else - aNameSpacePrefix.Truncate(); - - aNameSpaceURI = iter->mURI; - uri.Right(aProperty, uri.Length() - aNameSpaceURI.Length()); - return PR_TRUE; + NS_ENSURE_TRUE(iter->mPrefix, NS_ERROR_UNEXPECTED); + iter->mPrefix->ToUTF8String(qname); + qname.Append(':'); + qname += StringTail(uri, uri.Length() - iter->mURI.Length()); + return mQNames.Put(aResource, qname) ? NS_OK : NS_ERROR_FAILURE; } - + // Okay, so we don't have it in our map. Try to make one up. This // is very bogus. PRInt32 i = uri.RFindChar('#'); // first try a '#' @@ -236,30 +246,29 @@ nsRDFXMLSerializer::MakeQName(nsIRDFResource* aResource, if (i == -1) { // Okay, just punt and assume there is _no_ namespace on // this thing... - aNameSpaceURI.Truncate(); - aNameSpacePrefix.Truncate(); - aProperty = uri; - return PR_TRUE; + return mQNames.Put(aResource, uri) ? NS_OK : NS_ERROR_FAILURE; } } - // Take whatever is to the right of the '#' and call it the - // property. - aProperty.Truncate(); - uri.Right(aProperty, uri.Length() - (i + 1)); + // Take whatever is to the right of the '#' or '/' and call it the + // local name, make up a prefix. + qname.AssignLiteral("NS"); + qname.AppendInt(++mPrefixID, 10); + { + nsCOMPtr prefix = do_GetAtom(qname); + mNameSpaces.Put(StringHead(uri, i+1), prefix); + } + qname.Append(':'); + qname += StringTail(uri, uri.Length() - (i + 1)); - // Truncate the namespace URI down to the string up to and - // including the '#'. - aNameSpaceURI = uri; - aNameSpaceURI.Truncate(i + 1); - - // Just generate a random prefix - static PRInt32 gPrefixID = 0; - aNameSpacePrefix.AssignLiteral("NS"); - aNameSpacePrefix.AppendInt(++gPrefixID, 10); - return PR_FALSE; + return mQNames.Put(aResource, qname) ? NS_OK : NS_ERROR_FAILURE; } +nsresult +nsRDFXMLSerializer::GetQName(nsIRDFResource* aResource, nsCString& aQName) +{ + return mQNames.Get(aResource, &aQName) ? NS_OK : NS_ERROR_UNEXPECTED; +} PRBool nsRDFXMLSerializer::IsContainerProperty(nsIRDFResource* aProperty) @@ -370,42 +379,24 @@ nsRDFXMLSerializer::SerializeInlineAssertion(nsIOutputStream* aStream, nsIRDFResource* aProperty, nsIRDFLiteral* aValue) { - nsCAutoString property, nameSpacePrefix, nameSpaceURI; - nsCAutoString attr; - - PRBool wasDefinedAtGlobalScope = - MakeQName(aProperty, property, nameSpacePrefix, nameSpaceURI); - - if (nameSpacePrefix.Length()) { - attr.Append(nameSpacePrefix); - attr.Append(':'); - } - attr.Append(property); - nsresult rv; + nsCString qname; + rv = GetQName(aProperty, qname); + NS_ENSURE_SUCCESS(rv, rv); + rv = rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING("\n ")); if (NS_FAILED(rv)) return rv; - if (!wasDefinedAtGlobalScope && nameSpacePrefix.Length()) { - nsCAutoString nsutf8 = - NS_LITERAL_CSTRING("xmlns:") + - nameSpacePrefix + - NS_LITERAL_CSTRING("=\"") + - nameSpaceURI + - NS_LITERAL_CSTRING("\" "); - rv = rdf_BlockingWrite(aStream, nsutf8); - if (NS_FAILED(rv)) return rv; - } - const PRUnichar* value; aValue->GetValueConst(&value); NS_ConvertUTF16toUTF8 s(value); rdf_EscapeAttributeValue(s); - attr.AppendLiteral("=\""); - rv = rdf_BlockingWrite(aStream, attr); + rv = rdf_BlockingWrite(aStream, qname); + if (NS_FAILED(rv)) return rv; + rv = rdf_BlockingWrite(aStream, "=\"", 2); if (NS_FAILED(rv)) return rv; s.Append('"'); return rdf_BlockingWrite(aStream, s); @@ -417,33 +408,15 @@ nsRDFXMLSerializer::SerializeChildAssertion(nsIOutputStream* aStream, nsIRDFResource* aProperty, nsIRDFNode* aValue) { - nsCAutoString property, nameSpacePrefix, nameSpaceURI; - nsCAutoString tag; + nsCString qname; + nsresult rv = GetQName(aProperty, qname); + NS_ENSURE_SUCCESS(rv, rv); - PRBool wasDefinedAtGlobalScope = - MakeQName(aProperty, property, nameSpacePrefix, nameSpaceURI); - - if (nameSpacePrefix.Length()) { - tag.Append(nameSpacePrefix); - tag.Append(':'); - } - tag.Append(property); - - nsresult rv = rdf_BlockingWrite(aStream, " <", 5); + rv = rdf_BlockingWrite(aStream, " <", 5); if (NS_FAILED(rv)) return rv; - rv = rdf_BlockingWrite(aStream, tag); + rv = rdf_BlockingWrite(aStream, qname); if (NS_FAILED(rv)) return rv; - if (!wasDefinedAtGlobalScope && nameSpacePrefix.Length()) { - nsCAutoString out = NS_LITERAL_CSTRING(" xmlns:") + - nameSpacePrefix + - NS_LITERAL_CSTRING("=\"") + - nameSpaceURI + - NS_LITERAL_CSTRING("\""); - rv = rdf_BlockingWrite(aStream, out); - if (NS_FAILED(rv)) return rv; - } - nsCOMPtr resource; nsCOMPtr literal; nsCOMPtr number; @@ -516,8 +489,9 @@ nsRDFXMLSerializer::SerializeChildAssertion(nsIOutputStream* aStream, rv = rdf_BlockingWrite(aStream, "\n"); - return rdf_BlockingWrite(aStream, tag); + rv = rdf_BlockingWrite(aStream, qname); + if (NS_FAILED(rv)) return rv; + return rdf_BlockingWrite(aStream, ">\n", 2); no_close_tag: return NS_OK; @@ -600,7 +574,7 @@ nsRDFXMLSerializer::SerializeDescription(nsIOutputStream* aStream, nsresult rv; PRBool isTypedNode = PR_FALSE; - nsCAutoString nodeName, nameSpacePrefix, nameSpaceURI; + nsCString typeQName; nsCOMPtr typeNode; mDataSource->GetTarget(aResource, kRDF_type, PR_TRUE, getter_AddRefs(typeNode)); @@ -611,8 +585,7 @@ nsRDFXMLSerializer::SerializeDescription(nsIOutputStream* aStream, // just treat the description as if it weren't a typed node // after all and emit rdf:type as a normal property. This // seems preferable to using a bogus (invented) prefix. - isTypedNode = MakeQName(type, nodeName, - nameSpacePrefix, nameSpaceURI); + isTypedNode = NS_SUCCEEDED(GetQName(type, typeQName)); } } @@ -628,12 +601,7 @@ nsRDFXMLSerializer::SerializeDescription(nsIOutputStream* aStream, rv = rdf_BlockingWrite(aStream, NS_LITERAL_STRING(" <")); if (NS_FAILED(rv)) return rv; // Watch out for the default namespace! - if (!nameSpacePrefix.IsEmpty()) { - nameSpacePrefix.Append(':'); - rv = rdf_BlockingWrite(aStream, nameSpacePrefix); - if (NS_FAILED(rv)) return rv; - } - rv = rdf_BlockingWrite(aStream, nodeName); + rv = rdf_BlockingWrite(aStream, typeQName); if (NS_FAILED(rv)) return rv; } else { @@ -747,13 +715,9 @@ nsRDFXMLSerializer::SerializeDescription(nsIOutputStream* aStream, rv = rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING(" \n", 2); - rdf_BlockingWrite(aStream, nodeName); + rdf_BlockingWrite(aStream, typeQName); + if (NS_FAILED(rv)) return rv; + rdf_BlockingWrite(aStream, ">\n", 2); if (NS_FAILED(rv)) return rv; } else { @@ -1057,76 +1021,61 @@ nsRDFXMLSerializer::SerializeEpilogue(nsIOutputStream* aStream) return rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING("\n")); } +class QNameCollector : public rdfITripleVisitor { +public: + NS_DECL_ISUPPORTS + NS_DECL_RDFITRIPLEVISITOR + QNameCollector(nsRDFXMLSerializer* aParent) + : mParent(aParent){} +private: + nsRDFXMLSerializer* mParent; +}; + +NS_IMPL_ISUPPORTS1(QNameCollector, rdfITripleVisitor) nsresult -nsRDFXMLSerializer::CollectNamespaces() +QNameCollector::Visit(nsIRDFNode* aSubject, nsIRDFResource* aPredicate, + nsIRDFNode* aObject, PRBool aTruthValue) { - // Iterate through all the resources in the datasource, and all of - // the arcs-out of each, to collect the set of namespaces in use - nsCOMPtr resources; - mDataSource->GetAllResources(getter_AddRefs(resources)); - if (! resources) - return NS_ERROR_FAILURE; - - while (1) { - PRBool hasMore = PR_FALSE; - resources->HasMoreElements(&hasMore); - if (! hasMore) - break; - - nsCOMPtr isupports; - resources->GetNext(getter_AddRefs(isupports)); - - nsCOMPtr resource = - do_QueryInterface(isupports); - - if (! resource) - continue; - - nsCOMPtr arcs; - mDataSource->ArcLabelsOut(resource, getter_AddRefs(arcs)); - - if (! arcs) - continue; - - while (1) { - hasMore = PR_FALSE; - arcs->HasMoreElements(&hasMore); - if (! hasMore) - break; - - arcs->GetNext(getter_AddRefs(isupports)); - - nsCOMPtr property = - do_QueryInterface(isupports); - - if (! property) - continue; - - EnsureNameSpaceFor(property); + if (aPredicate == mParent->kRDF_type) { + // try to get a type QName for aObject, should be a resource + nsCOMPtr resType = do_QueryInterface(aObject); + if (!resType) { + // ignore error + return NS_OK; } + if (mParent->mQNames.Get(resType, nsnull)) { + return NS_OK; + } + mParent->RegisterQName(resType); + return NS_OK; } + if (mParent->mQNames.Get(aPredicate, nsnull)) { + return NS_OK; + } + if (aPredicate == mParent->kRDF_instanceOf || + aPredicate == mParent->kRDF_nextVal) + return NS_OK; + PRBool isOrdinal = PR_FALSE; + mParent->gRDFC->IsOrdinalProperty(aPredicate, &isOrdinal); + if (isOrdinal) + return NS_OK; + + mParent->RegisterQName(aPredicate); + return NS_OK; } - + nsresult -nsRDFXMLSerializer::EnsureNameSpaceFor(nsIRDFResource* aResource) +nsRDFXMLSerializer::CollectNamespaces() { - nsCAutoString property; - nsCAutoString nameSpacePrefix; - nsCAutoString nameSpaceURI; - - if (! MakeQName(aResource, property, nameSpacePrefix, nameSpaceURI)) { -#ifdef DEBUG_waterson - const char* s; - aResource->GetValueConst(&s); - printf("*** Creating namespace for %s\n", s); -#endif - nsCOMPtr prefix = do_GetAtom(nameSpacePrefix); - mNameSpaces.Put(nameSpaceURI, prefix); - } - - return NS_OK; + // Iterate over all Triples to get namespaces for subject resource types + // and Predicates and cache all the QNames we want to use. + nsCOMPtr collector = + new QNameCollector(this); + nsCOMPtr ds = do_QueryInterface(mDataSource); // XXX API + NS_ENSURE_TRUE(collector && ds, NS_ERROR_FAILURE); + return ds->VisitAllTriples(collector); } //---------------------------------------------------------------------- @@ -1135,6 +1084,7 @@ NS_IMETHODIMP nsRDFXMLSerializer::Serialize(nsIOutputStream* aStream) { nsresult rv; + NS_TIMELINE_START_TIMER("rdf/xml-ser"); rv = CollectNamespaces(); if (NS_FAILED(rv)) return rv; @@ -1173,7 +1123,11 @@ nsRDFXMLSerializer::Serialize(nsIOutputStream* aStream) break; } - return SerializeEpilogue(aStream); + rv = SerializeEpilogue(aStream); + NS_TIMELINE_STOP_TIMER("rdf/xml-ser"); + NS_TIMELINE_MARK("rdf/xml-ser"); + + return rv; } diff --git a/rdf/base/src/nsRDFXMLSerializer.h b/rdf/base/src/nsRDFXMLSerializer.h index 23c7309b85b2..58c6bcf868e5 100644 --- a/rdf/base/src/nsRDFXMLSerializer.h +++ b/rdf/base/src/nsRDFXMLSerializer.h @@ -22,6 +22,7 @@ * * Contributor(s): * Chris Waterson + * Axel Hecht * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), @@ -46,6 +47,9 @@ #include "nsNameSpaceMap.h" #include "nsXPIDLString.h" +#include "nsDataHashtable.h" +#include "rdfITripleVisitor.h" + class nsString; class nsIOutputStream; class nsIRDFContainerUtils; @@ -71,11 +75,10 @@ protected: virtual ~nsRDFXMLSerializer(); // Implementation methods - PRBool - MakeQName(nsIRDFResource* aResource, - nsCString& aPproperty, - nsCString& aNameSpacePrefix, - nsCString& aNameSpaceURI); + nsresult + RegisterQName(nsIRDFResource* aResource); + nsresult + GetQName(nsIRDFResource* aResource, nsCString& aQName); nsresult SerializeInlineAssertion(nsIOutputStream* aStream, @@ -121,9 +124,6 @@ protected: nsresult CollectNamespaces(); - nsresult - EnsureNameSpaceFor(nsIRDFResource* aResource); - PRBool IsA(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType); @@ -131,6 +131,12 @@ protected: nsNameSpaceMap mNameSpaces; nsXPIDLCString mBaseURLSpec; + // hash mapping resources to utf8-encoded QNames + nsDataHashtable mQNames; + friend class QNameCollector; + + PRUint32 mPrefixID; + static PRInt32 gRefCnt; static nsIRDFResource* kRDF_instanceOf; static nsIRDFResource* kRDF_type; diff --git a/rdf/base/src/rdfTriplesSerializer.cpp b/rdf/base/src/rdfTriplesSerializer.cpp new file mode 100644 index 000000000000..d1ea11f40e03 --- /dev/null +++ b/rdf/base/src/rdfTriplesSerializer.cpp @@ -0,0 +1,183 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla. + * + * The Initial Developer of the Original Code is + * Axel Hecht. + * Portions created by the Initial Developer are Copyright (C) 2005 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Axel Hecht + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsIOutputStream.h" +#include "nsReadableUtils.h" +#include "nsCRT.h" +#include "nsCOMPtr.h" +#include "nsString.h" +#include "nsPrintfCString.h" +#include "nsIBufferedStreams.h" +#include "nsNetCID.h" +#include "nsComponentManagerUtils.h" + +#include "rdfISerializer.h" +#include "rdfIDataSource.h" +#include "rdfITripleVisitor.h" + +#include "nsIRDFResource.h" +#include "nsIRDFLiteral.h" + +class TriplesVisitor : public rdfITripleVisitor +{ +public: + TriplesVisitor(nsIOutputStream* aOut) : mOut(aOut) {}; + NS_DECL_RDFITRIPLEVISITOR + NS_DECL_ISUPPORTS +protected: + nsresult writeResource(nsIRDFResource* aResource); + nsIOutputStream* mOut; +}; + +NS_IMPL_ISUPPORTS1(TriplesVisitor, rdfITripleVisitor) + +nsresult +TriplesVisitor::writeResource(nsIRDFResource *aResource) +{ + nsCString res; + PRUint32 writeCount, wroteCount; + mOut->Write("<", 1, &wroteCount); + NS_ENSURE_TRUE(wroteCount == 1, NS_ERROR_FAILURE); + nsresult rv = aResource->GetValueUTF8(res); + NS_ENSURE_SUCCESS(rv, rv); + writeCount = res.Length(); + mOut->Write(res.get(), writeCount, &wroteCount); + NS_ENSURE_TRUE(writeCount == wroteCount, NS_ERROR_FAILURE); + mOut->Write("> ", 2, &wroteCount); + NS_ENSURE_TRUE(wroteCount == 2, NS_ERROR_FAILURE); + return NS_OK; +} + +NS_IMETHODIMP +TriplesVisitor::Visit(nsIRDFNode *aSubject, nsIRDFResource *aPredicate, + nsIRDFNode *aObject, PRBool aTruthValue) +{ + nsCOMPtr subjectRes = do_QueryInterface(aSubject); + nsresult rv = NS_OK; + if (subjectRes) { + rv = writeResource(subjectRes); + } + if (NS_FAILED(rv)) { + return rv; + } + rv = writeResource(aPredicate); + if (NS_FAILED(rv)) { + return rv; + } + nsCOMPtr res = do_QueryInterface(aObject); + nsCOMPtr lit; + nsCOMPtr intLit; + PRUint32 wroteCount; + if (res) { + rv = writeResource(res); + } else if ((lit = do_QueryInterface(aObject)) != nsnull) { + const PRUnichar *value; + lit->GetValueConst(&value); + nsCAutoString object; + object.AppendLiteral("\""); + AppendUTF16toUTF8(value, object); + object.AppendLiteral("\" "); + PRUint32 writeCount = object.Length(); + rv = mOut->Write(object.get(), writeCount, &wroteCount); + NS_ENSURE_TRUE(writeCount == wroteCount, NS_ERROR_FAILURE); + } else if ((intLit = do_QueryInterface(aObject)) != nsnull) { + PRInt32 value; + intLit->GetValue(&value); + nsPrintfCString + object(128, + "\"%i\"^^ ", + value); + PRUint32 writeCount = object.Length(); + rv = mOut->Write(object.get(), writeCount, &wroteCount); + NS_ENSURE_TRUE(writeCount == wroteCount, NS_ERROR_FAILURE); + } + NS_ENSURE_SUCCESS(rv, rv); + return mOut->Write(".\n", 2, &wroteCount); +} + +class rdfTriplesSerializer : public rdfISerializer +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_RDFISERIALIZER + + rdfTriplesSerializer(); + +private: + ~rdfTriplesSerializer(); + +}; + +nsresult +NS_NewTriplesSerializer(rdfISerializer** aResult) +{ + NS_PRECONDITION(aResult != nsnull, "null ptr"); + if (! aResult) + return NS_ERROR_NULL_POINTER; + + *aResult = new rdfTriplesSerializer(); + if (! *aResult) + return NS_ERROR_OUT_OF_MEMORY; + NS_ADDREF(*aResult); + return NS_OK; +} + +NS_IMPL_ISUPPORTS1(rdfTriplesSerializer, rdfISerializer) + +rdfTriplesSerializer::rdfTriplesSerializer() +{ +} + +rdfTriplesSerializer::~rdfTriplesSerializer() +{ +} + +NS_IMETHODIMP +rdfTriplesSerializer::Serialize(rdfIDataSource *aDataSource, + nsIOutputStream *aOut) +{ + nsresult rv; + nsCOMPtr bufout = + do_CreateInstance(NS_BUFFEREDOUTPUTSTREAM_CONTRACTID, &rv); + NS_ENSURE_SUCCESS(rv, rv); + rv = bufout->Init(aOut, 1024); + NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr tv = new TriplesVisitor(bufout); + NS_ENSURE_TRUE(tv, NS_ERROR_OUT_OF_MEMORY); + return aDataSource->VisitAllTriples(tv); +} diff --git a/rdf/build/nsRDFCID.h b/rdf/build/nsRDFCID.h index 564f8a655b44..e239fabd7328 100644 --- a/rdf/build/nsRDFCID.h +++ b/rdf/build/nsRDFCID.h @@ -105,4 +105,8 @@ #define NS_RDFXMLPARSER_CID \ { 0xa4048e94, 0x1dd1, 0x11b2, { 0xa6, 0x76, 0x8a, 0x06, 0xc0, 0x86, 0xcc, 0x7d } } +// {0a5cd734-eb65-4d14-88a0-9f0bb2aba206} +#define NS_RDFNTRIPLES_SERIALIZER_CID \ +{ 0x0a5cd734, 0xeb65, 0x4d14, { 0x88, 0xa0, 0x9f, 0x0b, 0xb2, 0xab, 0xa2, 0x06 } } + #endif // nsRDFCID_h__ diff --git a/rdf/build/nsRDFModule.cpp b/rdf/build/nsRDFModule.cpp index eb1b8df3a33d..69863b6d3d1e 100644 --- a/rdf/build/nsRDFModule.cpp +++ b/rdf/build/nsRDFModule.cpp @@ -57,6 +57,8 @@ #include "nsRDFXMLParser.h" #include "nsRDFXMLSerializer.h" +#include "rdfISerializer.h" + //---------------------------------------------------------------------- // Functions used to create new instances of a given object by the @@ -101,6 +103,36 @@ MAKE_CTOR(RDFContainerUtils,RDFContainerUtils,RDFContainerUtils) MAKE_CTOR(RDFContentSink,RDFContentSink,RDFContentSink) MAKE_CTOR(RDFDefaultResource,DefaultResource,RDFResource) +#define MAKE_RDF_CTOR(_func,_new,_ifname) \ +static NS_IMETHODIMP \ +CreateNew##_func(nsISupports* aOuter, REFNSIID aIID, void **aResult) \ +{ \ + if (!aResult) { \ + return NS_ERROR_INVALID_POINTER; \ + } \ + if (aOuter) { \ + *aResult = nsnull; \ + return NS_ERROR_NO_AGGREGATION; \ + } \ + rdfI##_ifname* inst; \ + nsresult rv = NS_New##_new(&inst); \ + if (NS_FAILED(rv)) { \ + *aResult = nsnull; \ + return rv; \ + } \ + rv = inst->QueryInterface(aIID, aResult); \ + if (NS_FAILED(rv)) { \ + *aResult = nsnull; \ + } \ + NS_RELEASE(inst); /* get rid of extra refcnt */ \ + return rv; \ +} + +extern nsresult +NS_NewTriplesSerializer(rdfISerializer** aResult); + +MAKE_RDF_CTOR(TriplesSerializer, TriplesSerializer, Serializer) + // The list of components we register static const nsModuleComponentInfo components[] = { // register our build-in datasources: @@ -175,6 +207,12 @@ static const nsModuleComponentInfo components[] = nsRDFXMLSerializer::Create }, + { "RDF/NTriples Serializer", + NS_RDFNTRIPLES_SERIALIZER_CID, + NS_RDF_SERIALIZER "ntriples", + CreateNewTriplesSerializer + }, + // XXX move this to XPFE at some point. { "Local Store", NS_LOCALSTORE_CID, NS_LOCALSTORE_CONTRACTID, NS_NewLocalStore }, diff --git a/rdf/tests/Makefile.in b/rdf/tests/Makefile.in index b7910973b03e..9f07f56ad62c 100644 --- a/rdf/tests/Makefile.in +++ b/rdf/tests/Makefile.in @@ -42,7 +42,7 @@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk -DIRS = rdfcat rdfpoll +DIRS = rdfcat rdfpoll triplescat include $(topsrcdir)/config/rules.mk diff --git a/rdf/tests/triplescat/Makefile.in b/rdf/tests/triplescat/Makefile.in new file mode 100644 index 000000000000..81a0ef1d2616 --- /dev/null +++ b/rdf/tests/triplescat/Makefile.in @@ -0,0 +1,66 @@ +# +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Axel Hecht +# +# Alternatively, the contents of this file may be used under the terms of +# either of the GNU General Public License Version 2 or later (the "GPL"), +# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +PROGRAM = triplescat$(BIN_SUFFIX) +CPPSRCS = triplescat.cpp +REQUIRES = xpcom \ + rdf \ + necko \ + string \ + $(NULL) + +LIBS = \ + $(LIBS_DIR) \ + $(XPCOM_LIBS) \ + $(NSPR_LIBS) \ + $(NULL) + +ifeq ($(OS_ARCH),WINNT) +MAPFILE=triplescat.map +endif + +include $(topsrcdir)/config/rules.mk + +CXXFLAGS += $(MOZ_TOOLKIT_REGISTRY_CFLAGS) diff --git a/rdf/tests/triplescat/triplescat.cpp b/rdf/tests/triplescat/triplescat.cpp new file mode 100644 index 000000000000..521c6353b4b3 --- /dev/null +++ b/rdf/tests/triplescat/triplescat.cpp @@ -0,0 +1,199 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Axel Hecht + * Chase Tingley + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +/** + * A simple test program that reads in RDF/XML into an in-memory data + * source, then serializes NTriples format back to stdout (or none). + * + * The program takes a single parameter: the URL from which to read, + * plus an optional parameter -q + */ + +#include +#include "nsXPCOM.h" +#include "nsCOMPtr.h" +//#include "nsString.h" +#include "nsIComponentManager.h" +#include "nsComponentManagerUtils.h" +#include "nsServiceManagerUtils.h" +#include "nsIEventQueueService.h" +#include "nsIIOService.h" +#include "nsIInputStream.h" +#include "nsIOutputStream.h" +#include "nsIRDFCompositeDataSource.h" +#include "nsIRDFNode.h" +#include "nsIRDFRemoteDataSource.h" +#include "nsIRDFService.h" +#include "nsIRDFXMLSource.h" +#include "nsIServiceManager.h" +#include "nsIStreamListener.h" +#include "nsIURL.h" +#include "nsRDFCID.h" +#include "plevent.h" +#include "plstr.h" +#include "prio.h" +#include "prthread.h" + +#include "rdf.h" +#include "rdfIDataSource.h" +#include "rdfITripleVisitor.h" +#include "rdfISerializer.h" + +//////////////////////////////////////////////////////////////////////// +// Blatantly stolen from netwerk/test/ +#define RETURN_IF_FAILED(rv, step) \ + PR_BEGIN_MACRO \ + if (NS_FAILED(rv)) { \ + printf(">>> %s failed: rv=%x\n", step, rv); \ + return rv;\ + } \ + PR_END_MACRO + +//////////////////////////////////////////////////////////////////////// + +class ConsoleOutputStreamImpl : public nsIOutputStream +{ +public: + ConsoleOutputStreamImpl(void) {} + virtual ~ConsoleOutputStreamImpl(void) {} + + // nsISupports interface + NS_DECL_ISUPPORTS + + // nsIBaseStream interface + NS_IMETHOD Close(void) { + return NS_OK; + } + + // nsIOutputStream interface + NS_IMETHOD Write(const char* aBuf, PRUint32 aCount, PRUint32 *aWriteCount) { + PR_Write(PR_GetSpecialFD(PR_StandardOutput), aBuf, aCount); + *aWriteCount = aCount; + return NS_OK; + } + + NS_IMETHOD + WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval) { + NS_NOTREACHED("WriteFrom"); + return NS_ERROR_NOT_IMPLEMENTED; + } + + NS_IMETHOD + WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval) { + NS_NOTREACHED("WriteSegments"); + return NS_ERROR_NOT_IMPLEMENTED; + } + + NS_IMETHOD + IsNonBlocking(PRBool *aNonBlocking) { + NS_NOTREACHED("IsNonBlocking"); + return NS_ERROR_NOT_IMPLEMENTED; + } + + NS_IMETHOD Flush(void) { + PR_Sync(PR_GetSpecialFD(PR_StandardOutput)); + return NS_OK; + } +}; + +NS_IMPL_ISUPPORTS1(ConsoleOutputStreamImpl, nsIOutputStream) + +//////////////////////////////////////////////////////////////////////// + +int +main(int argc, char** argv) +{ + nsresult rv; + + if (argc < 2) { + fprintf(stderr, "usage: %s \n", argv[0]); + return 1; + } + + NS_InitXPCOM2(nsnull, nsnull, nsnull); + + // Get netlib off the floor... + nsCOMPtr theEventQueueService = + do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv); + RETURN_IF_FAILED(rv, "EventQueueService"); + + nsIEventQueue* eq = nsnull; + rv = theEventQueueService->GetThreadEventQueue(NS_CURRENT_THREAD, &eq); + RETURN_IF_FAILED(rv, "GetThreadEventQueue"); + + // Create a stream data source and initialize it on argv[1], which + // is hopefully a "file:" URL. + nsCOMPtr ds = + do_CreateInstance(NS_RDF_DATASOURCE_CONTRACTID_PREFIX "xml-datasource", + &rv); + RETURN_IF_FAILED(rv, "RDF/XML datasource creation"); + + nsCOMPtr remote = do_QueryInterface(ds, &rv); + RETURN_IF_FAILED(rv, "QI to nsIRDFRemoteDataSource"); + + rv = remote->Init(argv[1]); + RETURN_IF_FAILED(rv, "datasource initialization"); + + // Okay, this should load the XML file... + rv = remote->Refresh(PR_FALSE); + RETURN_IF_FAILED(rv, "datasource refresh"); + + // Pump events until the load is finished + PRBool done = PR_FALSE; + while (!done) { + eq->ProcessPendingEvents(); + remote->GetLoaded(&done); + } + + nsCOMPtr rdfds = do_QueryInterface(ds, &rv); + RETURN_IF_FAILED(rv, "QI to rdIDataSource"); + { + nsCOMPtr out = new ConsoleOutputStreamImpl(); + nsCOMPtr ser = + do_CreateInstance(NS_RDF_SERIALIZER "ntriples", &rv); + RETURN_IF_FAILED(rv, "Creation of NTriples Serializer"); + rv = ser->Serialize(rdfds, out); + RETURN_IF_FAILED(rv, "Serialization to NTriples"); + out->Close(); + } + + theEventQueueService->DestroyThreadEventQueue(); + + return NS_OK; +}