1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=4 sw=4 et tw=80:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is mozilla.org Code.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * Netscape Communications Corporation.
21 : * Portions created by the Initial Developer are Copyright (C) 1999
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : * Chris Waterson <waterson@netscape.com>
26 : * Axel Hecht <axel@pike.org>
27 : *
28 : * Alternatively, the contents of this file may be used under the terms of
29 : * either of the GNU General Public License Version 2 or later (the "GPL"),
30 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 : * in which case the provisions of the GPL or the LGPL are applicable instead
32 : * of those above. If you wish to allow use of your version of this file only
33 : * under the terms of either the GPL or the LGPL, and not to allow others to
34 : * use your version of this file under the terms of the MPL, indicate your
35 : * decision by deleting the provisions above and replace them with the notice
36 : * and other provisions required by the GPL or the LGPL. If you do not delete
37 : * the provisions above, a recipient may use your version of this file under
38 : * the terms of any one of the MPL, the GPL or the LGPL.
39 : *
40 : * ***** END LICENSE BLOCK ***** */
41 :
42 : #include "nsRDFXMLSerializer.h"
43 :
44 : #include "nsIAtom.h"
45 : #include "nsIOutputStream.h"
46 : #include "nsIRDFService.h"
47 : #include "nsIRDFContainerUtils.h"
48 : #include "nsIServiceManager.h"
49 : #include "nsString.h"
50 : #include "nsXPIDLString.h"
51 : #include "nsTArray.h"
52 : #include "rdf.h"
53 : #include "rdfutil.h"
54 :
55 : #include "rdfIDataSource.h"
56 :
57 : PRInt32 nsRDFXMLSerializer::gRefCnt = 0;
58 : nsIRDFContainerUtils* nsRDFXMLSerializer::gRDFC;
59 : nsIRDFResource* nsRDFXMLSerializer::kRDF_instanceOf;
60 : nsIRDFResource* nsRDFXMLSerializer::kRDF_type;
61 : nsIRDFResource* nsRDFXMLSerializer::kRDF_nextVal;
62 : nsIRDFResource* nsRDFXMLSerializer::kRDF_Bag;
63 : nsIRDFResource* nsRDFXMLSerializer::kRDF_Seq;
64 : nsIRDFResource* nsRDFXMLSerializer::kRDF_Alt;
65 :
66 : static const char kRDFDescriptionOpen[] = " <RDF:Description";
67 : static const char kIDAttr[] = " RDF:ID=\"";
68 : static const char kAboutAttr[] = " RDF:about=\"";
69 : static const char kRDFDescriptionClose[] = " </RDF:Description>\n";
70 : static const char kRDFResource1[] = " RDF:resource=\"";
71 : static const char kRDFResource2[] = "\"/>\n";
72 : static const char kRDFParseTypeInteger[] = " NC:parseType=\"Integer\">";
73 : static const char kRDFParseTypeDate[] = " NC:parseType=\"Date\">";
74 : static const char kRDFUnknown[] = "><!-- unknown node type -->";
75 :
76 : nsresult
77 19 : nsRDFXMLSerializer::Create(nsISupports* aOuter, REFNSIID aIID, void** aResult)
78 : {
79 19 : if (aOuter)
80 0 : return NS_ERROR_NO_AGGREGATION;
81 :
82 38 : nsCOMPtr<nsIRDFXMLSerializer> result = new nsRDFXMLSerializer();
83 19 : if (! result)
84 0 : return NS_ERROR_OUT_OF_MEMORY;
85 : // The serializer object is here, addref gRefCnt so that the
86 : // destructor can safely release it.
87 19 : gRefCnt++;
88 :
89 : nsresult rv;
90 19 : rv = result->QueryInterface(aIID, aResult);
91 :
92 19 : if (NS_FAILED(rv)) return rv;
93 :
94 19 : if (gRefCnt == 1) do {
95 38 : nsCOMPtr<nsIRDFService> rdf = do_GetService("@mozilla.org/rdf/rdf-service;1", &rv);
96 19 : if (NS_FAILED(rv)) break;
97 :
98 38 : rv = rdf->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "instanceOf"),
99 19 : &kRDF_instanceOf);
100 19 : if (NS_FAILED(rv)) break;
101 :
102 38 : rv = rdf->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "type"),
103 19 : &kRDF_type);
104 19 : if (NS_FAILED(rv)) break;
105 :
106 38 : rv = rdf->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "nextVal"),
107 19 : &kRDF_nextVal);
108 19 : if (NS_FAILED(rv)) break;
109 :
110 38 : rv = rdf->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Bag"),
111 19 : &kRDF_Bag);
112 19 : if (NS_FAILED(rv)) break;
113 :
114 38 : rv = rdf->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Seq"),
115 19 : &kRDF_Seq);
116 19 : if (NS_FAILED(rv)) break;
117 :
118 38 : rv = rdf->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "Alt"),
119 19 : &kRDF_Alt);
120 19 : if (NS_FAILED(rv)) break;
121 :
122 19 : rv = CallGetService("@mozilla.org/rdf/container-utils;1", &gRDFC);
123 19 : if (NS_FAILED(rv)) break;
124 : } while (0);
125 :
126 19 : return rv;
127 : }
128 :
129 19 : nsRDFXMLSerializer::nsRDFXMLSerializer()
130 : {
131 19 : MOZ_COUNT_CTOR(nsRDFXMLSerializer);
132 19 : }
133 :
134 57 : nsRDFXMLSerializer::~nsRDFXMLSerializer()
135 : {
136 19 : MOZ_COUNT_DTOR(nsRDFXMLSerializer);
137 :
138 19 : if (--gRefCnt == 0) {
139 19 : NS_IF_RELEASE(kRDF_Bag);
140 19 : NS_IF_RELEASE(kRDF_Seq);
141 19 : NS_IF_RELEASE(kRDF_Alt);
142 19 : NS_IF_RELEASE(kRDF_instanceOf);
143 19 : NS_IF_RELEASE(kRDF_type);
144 19 : NS_IF_RELEASE(kRDF_nextVal);
145 19 : NS_IF_RELEASE(gRDFC);
146 : }
147 76 : }
148 :
149 266 : NS_IMPL_ISUPPORTS2(nsRDFXMLSerializer, nsIRDFXMLSerializer, nsIRDFXMLSource)
150 :
151 : NS_IMETHODIMP
152 19 : nsRDFXMLSerializer::Init(nsIRDFDataSource* aDataSource)
153 : {
154 19 : if (! aDataSource)
155 0 : return NS_ERROR_NULL_POINTER;
156 :
157 19 : mDataSource = aDataSource;
158 19 : mDataSource->GetURI(getter_Copies(mBaseURLSpec));
159 :
160 : // Add the ``RDF'' prefix, by default.
161 38 : nsCOMPtr<nsIAtom> prefix;
162 :
163 19 : prefix = do_GetAtom("RDF");
164 19 : AddNameSpace(prefix, NS_LITERAL_STRING("http://www.w3.org/1999/02/22-rdf-syntax-ns#"));
165 :
166 19 : prefix = do_GetAtom("NC");
167 19 : AddNameSpace(prefix, NS_LITERAL_STRING("http://home.netscape.com/NC-rdf#"));
168 :
169 19 : mQNames.Init();
170 19 : mPrefixID = 0;
171 :
172 19 : return NS_OK;
173 : }
174 :
175 : NS_IMETHODIMP
176 38 : nsRDFXMLSerializer::AddNameSpace(nsIAtom* aPrefix, const nsAString& aURI)
177 : {
178 76 : nsCOMPtr<nsIAtom> prefix = aPrefix;
179 38 : if (!prefix) {
180 : // Make up a prefix, we don't want default namespaces, so
181 : // that we can use QNames for elements and attributes alike.
182 0 : prefix = EnsureNewPrefix();
183 : }
184 38 : mNameSpaces.Put(aURI, prefix);
185 38 : return NS_OK;
186 : }
187 :
188 : static nsresult
189 5163 : rdf_BlockingWrite(nsIOutputStream* stream, const char* buf, PRUint32 size)
190 : {
191 5163 : PRUint32 written = 0;
192 5163 : PRUint32 remaining = size;
193 15489 : while (remaining > 0) {
194 : nsresult rv;
195 : PRUint32 cb;
196 :
197 5163 : if (NS_FAILED(rv = stream->Write(buf + written, remaining, &cb)))
198 0 : return rv;
199 :
200 5163 : written += cb;
201 5163 : remaining -= cb;
202 : }
203 5163 : return NS_OK;
204 : }
205 :
206 : static nsresult
207 2798 : rdf_BlockingWrite(nsIOutputStream* stream, const nsCSubstring& s)
208 : {
209 2798 : return rdf_BlockingWrite(stream, s.BeginReading(), s.Length());
210 : }
211 :
212 : static nsresult
213 0 : rdf_BlockingWrite(nsIOutputStream* stream, const nsAString& s)
214 : {
215 0 : NS_ConvertUTF16toUTF8 utf8(s);
216 0 : return rdf_BlockingWrite(stream, utf8.get(), utf8.Length());
217 : }
218 :
219 : already_AddRefed<nsIAtom>
220 0 : nsRDFXMLSerializer::EnsureNewPrefix()
221 : {
222 0 : nsAutoString qname;
223 0 : nsCOMPtr<nsIAtom> prefix;
224 : bool isNewPrefix;
225 0 : do {
226 0 : isNewPrefix = true;
227 0 : qname.AssignLiteral("NS");
228 0 : qname.AppendInt(++mPrefixID, 10);
229 0 : prefix = do_GetAtom(qname);
230 0 : nsNameSpaceMap::const_iterator iter = mNameSpaces.first();
231 0 : while (iter != mNameSpaces.last() && isNewPrefix) {
232 0 : isNewPrefix = (iter->mPrefix != prefix);
233 0 : ++iter;
234 : }
235 0 : } while (!isNewPrefix);
236 0 : nsIAtom* outPrefix = nsnull;
237 0 : prefix.swap(outPrefix);
238 0 : return outPrefix;
239 : }
240 :
241 : // This converts a property resource (like
242 : // "http://www.w3.org/TR/WD-rdf-syntax#Description") into a QName
243 : // ("RDF:Description"), and registers the namespace, if it's made up.
244 :
245 : nsresult
246 205 : nsRDFXMLSerializer::RegisterQName(nsIRDFResource* aResource)
247 : {
248 410 : nsCAutoString uri, qname;
249 205 : aResource->GetValueUTF8(uri);
250 :
251 205 : nsNameSpaceMap::const_iterator iter = mNameSpaces.GetNameSpaceOf(uri);
252 205 : if (iter != mNameSpaces.last()) {
253 205 : NS_ENSURE_TRUE(iter->mPrefix, NS_ERROR_UNEXPECTED);
254 205 : iter->mPrefix->ToUTF8String(qname);
255 205 : qname.Append(':');
256 205 : qname += StringTail(uri, uri.Length() - iter->mURI.Length());
257 205 : return mQNames.Put(aResource, qname) ? NS_OK : NS_ERROR_FAILURE;
258 : }
259 :
260 : // Okay, so we don't have it in our map. Try to make one up. This
261 : // is very bogus.
262 0 : PRInt32 i = uri.RFindChar('#'); // first try a '#'
263 0 : if (i == -1) {
264 0 : i = uri.RFindChar('/');
265 0 : if (i == -1) {
266 : // Okay, just punt and assume there is _no_ namespace on
267 : // this thing...
268 0 : return mQNames.Put(aResource, uri) ? NS_OK : NS_ERROR_FAILURE;
269 : }
270 : }
271 :
272 : // Take whatever is to the right of the '#' or '/' and call it the
273 : // local name, make up a prefix.
274 0 : nsCOMPtr<nsIAtom> prefix = EnsureNewPrefix();
275 0 : mNameSpaces.Put(StringHead(uri, i+1), prefix);
276 0 : prefix->ToUTF8String(qname);
277 0 : qname.Append(':');
278 0 : qname += StringTail(uri, uri.Length() - (i + 1));
279 :
280 0 : return mQNames.Put(aResource, qname) ? NS_OK : NS_ERROR_FAILURE;
281 : }
282 :
283 : nsresult
284 632 : nsRDFXMLSerializer::GetQName(nsIRDFResource* aResource, nsCString& aQName)
285 : {
286 632 : return mQNames.Get(aResource, &aQName) ? NS_OK : NS_ERROR_UNEXPECTED;
287 : }
288 :
289 : bool
290 1174 : nsRDFXMLSerializer::IsContainerProperty(nsIRDFResource* aProperty)
291 : {
292 : // Return `true' if the property is an internal property related
293 : // to being a container.
294 1174 : if (aProperty == kRDF_instanceOf)
295 29 : return true;
296 :
297 1145 : if (aProperty == kRDF_nextVal)
298 29 : return true;
299 :
300 1116 : bool isOrdinal = false;
301 1116 : gRDFC->IsOrdinalProperty(aProperty, &isOrdinal);
302 1116 : if (isOrdinal)
303 93 : return true;
304 :
305 1023 : return false;
306 : }
307 :
308 :
309 : // convert '&', '<', and '>' into "&", "<", and ">", respectively.
310 : static const char amp[] = "&";
311 : static const char lt[] = "<";
312 : static const char gt[] = ">";
313 : static const char quot[] = """;
314 :
315 : static void
316 1112 : rdf_EscapeAmpersandsAndAngleBrackets(nsCString& s)
317 : {
318 : PRUint32 newLength, origLength;
319 1112 : newLength = origLength = s.Length();
320 :
321 : // Compute the length of the result string.
322 1112 : const char* start = s.BeginReading();
323 1112 : const char* end = s.EndReading();
324 1112 : const char* c = start;
325 30240 : while (c != end) {
326 28016 : switch (*c) {
327 : case '&' :
328 102 : newLength += sizeof(amp) - 2;
329 102 : break;
330 : case '<':
331 : case '>':
332 0 : newLength += sizeof(gt) - 2;
333 0 : break;
334 : default:
335 27914 : break;
336 : }
337 28016 : ++c;
338 : }
339 1112 : if (newLength == origLength) {
340 : // nothing to escape
341 1010 : return;
342 : }
343 :
344 : // escape the chars from the end back to the front.
345 102 : s.SetLength(newLength);
346 :
347 : // Buffer might have changed, get the pointers again
348 102 : start = s.BeginReading(); // begin of string
349 102 : c = start + origLength - 1; // last char in original string
350 102 : char* w = s.EndWriting() - 1; // last char in grown buffer
351 6392 : while (c >= start) {
352 6188 : switch (*c) {
353 : case '&' :
354 102 : w -= 4;
355 102 : nsCharTraits<char>::copy(w, amp, sizeof(amp) - 1);
356 102 : break;
357 : case '<':
358 0 : w -= 3;
359 0 : nsCharTraits<char>::copy(w, lt, sizeof(lt) - 1);
360 0 : break;
361 : case '>':
362 0 : w -= 3;
363 0 : nsCharTraits<char>::copy(w, gt, sizeof(gt) - 1);
364 0 : break;
365 : default:
366 6086 : *w = *c;
367 : }
368 6188 : --w;
369 6188 : --c;
370 : }
371 : }
372 :
373 : // convert '"' to """
374 : static void
375 1112 : rdf_EscapeQuotes(nsCString& s)
376 : {
377 1112 : PRInt32 i = 0;
378 2224 : while ((i = s.FindChar('"', i)) != -1) {
379 0 : s.Replace(i, 1, quot, sizeof(quot) - 1);
380 0 : i += sizeof(quot) - 2;
381 : }
382 1112 : }
383 :
384 : static void
385 1112 : rdf_EscapeAttributeValue(nsCString& s)
386 : {
387 1112 : rdf_EscapeAmpersandsAndAngleBrackets(s);
388 1112 : rdf_EscapeQuotes(s);
389 1112 : }
390 :
391 :
392 : nsresult
393 410 : nsRDFXMLSerializer::SerializeInlineAssertion(nsIOutputStream* aStream,
394 : nsIRDFResource* aResource,
395 : nsIRDFResource* aProperty,
396 : nsIRDFLiteral* aValue)
397 : {
398 : nsresult rv;
399 820 : nsCString qname;
400 410 : rv = GetQName(aProperty, qname);
401 410 : NS_ENSURE_SUCCESS(rv, rv);
402 :
403 : rv = rdf_BlockingWrite(aStream,
404 410 : NS_LITERAL_CSTRING("\n "));
405 410 : if (NS_FAILED(rv)) return rv;
406 :
407 : const PRUnichar* value;
408 410 : aValue->GetValueConst(&value);
409 820 : NS_ConvertUTF16toUTF8 s(value);
410 :
411 410 : rdf_EscapeAttributeValue(s);
412 :
413 410 : rv = rdf_BlockingWrite(aStream, qname);
414 410 : if (NS_FAILED(rv)) return rv;
415 410 : rv = rdf_BlockingWrite(aStream, "=\"", 2);
416 410 : if (NS_FAILED(rv)) return rv;
417 410 : s.Append('"');
418 410 : return rdf_BlockingWrite(aStream, s);
419 : }
420 :
421 : nsresult
422 222 : nsRDFXMLSerializer::SerializeChildAssertion(nsIOutputStream* aStream,
423 : nsIRDFResource* aResource,
424 : nsIRDFResource* aProperty,
425 : nsIRDFNode* aValue)
426 : {
427 444 : nsCString qname;
428 222 : nsresult rv = GetQName(aProperty, qname);
429 222 : NS_ENSURE_SUCCESS(rv, rv);
430 :
431 222 : rv = rdf_BlockingWrite(aStream, " <", 5);
432 222 : if (NS_FAILED(rv)) return rv;
433 222 : rv = rdf_BlockingWrite(aStream, qname);
434 222 : if (NS_FAILED(rv)) return rv;
435 :
436 444 : nsCOMPtr<nsIRDFResource> resource;
437 444 : nsCOMPtr<nsIRDFLiteral> literal;
438 444 : nsCOMPtr<nsIRDFInt> number;
439 444 : nsCOMPtr<nsIRDFDate> date;
440 :
441 222 : if ((resource = do_QueryInterface(aValue)) != nsnull) {
442 444 : nsCAutoString uri;
443 222 : resource->GetValueUTF8(uri);
444 :
445 222 : rdf_MakeRelativeRef(mBaseURLSpec, uri);
446 222 : rdf_EscapeAttributeValue(uri);
447 :
448 : rv = rdf_BlockingWrite(aStream, kRDFResource1,
449 222 : sizeof(kRDFResource1) - 1);
450 222 : if (NS_FAILED(rv)) return rv;
451 222 : rv = rdf_BlockingWrite(aStream, uri);
452 222 : if (NS_FAILED(rv)) return rv;
453 : rv = rdf_BlockingWrite(aStream, kRDFResource2,
454 222 : sizeof(kRDFResource2) - 1);
455 222 : if (NS_FAILED(rv)) return rv;
456 :
457 222 : goto no_close_tag;
458 : }
459 0 : else if ((literal = do_QueryInterface(aValue)) != nsnull) {
460 : const PRUnichar *value;
461 0 : literal->GetValueConst(&value);
462 0 : NS_ConvertUTF16toUTF8 s(value);
463 :
464 0 : rdf_EscapeAmpersandsAndAngleBrackets(s);
465 :
466 0 : rv = rdf_BlockingWrite(aStream, ">", 1);
467 0 : if (NS_FAILED(rv)) return rv;
468 0 : rv = rdf_BlockingWrite(aStream, s);
469 0 : if (NS_FAILED(rv)) return rv;
470 : }
471 0 : else if ((number = do_QueryInterface(aValue)) != nsnull) {
472 : PRInt32 value;
473 0 : number->GetValue(&value);
474 :
475 0 : nsCAutoString n;
476 0 : n.AppendInt(value);
477 :
478 : rv = rdf_BlockingWrite(aStream, kRDFParseTypeInteger,
479 0 : sizeof(kRDFParseTypeInteger) - 1);
480 0 : if (NS_FAILED(rv)) return rv;
481 0 : rv = rdf_BlockingWrite(aStream, n);
482 0 : if (NS_FAILED(rv)) return rv;
483 : }
484 0 : else if ((date = do_QueryInterface(aValue)) != nsnull) {
485 : PRTime value;
486 0 : date->GetValue(&value);
487 :
488 0 : nsCAutoString s;
489 0 : rdf_FormatDate(value, s);
490 :
491 : rv = rdf_BlockingWrite(aStream, kRDFParseTypeDate,
492 0 : sizeof(kRDFParseTypeDate) - 1);
493 0 : if (NS_FAILED(rv)) return rv;
494 0 : rv = rdf_BlockingWrite(aStream, s);
495 0 : if (NS_FAILED(rv)) return rv;
496 : }
497 : else {
498 : // XXX it doesn't support nsIRDFResource _or_ nsIRDFLiteral???
499 : // We should serialize nsIRDFInt, nsIRDFDate, etc...
500 0 : NS_WARNING("unknown RDF node type");
501 :
502 0 : rv = rdf_BlockingWrite(aStream, kRDFUnknown, sizeof(kRDFUnknown) - 1);
503 0 : if (NS_FAILED(rv)) return rv;
504 : }
505 :
506 0 : rv = rdf_BlockingWrite(aStream, "</", 2);
507 0 : if (NS_FAILED(rv)) return rv;
508 0 : rv = rdf_BlockingWrite(aStream, qname);
509 0 : if (NS_FAILED(rv)) return rv;
510 0 : return rdf_BlockingWrite(aStream, ">\n", 2);
511 :
512 : no_close_tag:
513 222 : return NS_OK;
514 : }
515 :
516 : nsresult
517 1023 : nsRDFXMLSerializer::SerializeProperty(nsIOutputStream* aStream,
518 : nsIRDFResource* aResource,
519 : nsIRDFResource* aProperty,
520 : bool aInline,
521 : PRInt32* aSkipped)
522 : {
523 1023 : nsresult rv = NS_OK;
524 :
525 1023 : PRInt32 skipped = 0;
526 :
527 2046 : nsCOMPtr<nsISimpleEnumerator> assertions;
528 1023 : mDataSource->GetTargets(aResource, aProperty, true, getter_AddRefs(assertions));
529 1023 : if (! assertions)
530 0 : return NS_ERROR_FAILURE;
531 :
532 : // Serializing the assertion inline is ok as long as the property has
533 : // only one target value, and it is a literal that doesn't include line
534 : // breaks.
535 1023 : bool needsChild = false;
536 :
537 1055 : while (1) {
538 2078 : bool hasMore = false;
539 2078 : assertions->HasMoreElements(&hasMore);
540 2078 : if (! hasMore)
541 1023 : break;
542 :
543 2110 : nsCOMPtr<nsISupports> isupports;
544 1055 : assertions->GetNext(getter_AddRefs(isupports));
545 2110 : nsCOMPtr<nsIRDFLiteral> literal = do_QueryInterface(isupports);
546 1055 : needsChild |= (!literal);
547 :
548 1055 : if (!needsChild) {
549 611 : assertions->HasMoreElements(&needsChild);
550 611 : if (!needsChild) {
551 611 : const PRUnichar* literalVal = nsnull;
552 611 : literal->GetValueConst(&literalVal);
553 611 : if (literalVal) {
554 7328 : for (; *literalVal; literalVal++) {
555 6717 : if (*literalVal == PRUnichar('\n') ||
556 : *literalVal == PRUnichar('\r')) {
557 0 : needsChild = true;
558 0 : break;
559 : }
560 : }
561 : }
562 : }
563 : }
564 :
565 1055 : if (aInline && !needsChild) {
566 410 : rv = SerializeInlineAssertion(aStream, aResource, aProperty, literal);
567 : }
568 645 : else if (!aInline && needsChild) {
569 444 : nsCOMPtr<nsIRDFNode> value = do_QueryInterface(isupports);
570 444 : rv = SerializeChildAssertion(aStream, aResource, aProperty, value);
571 : }
572 : else {
573 423 : ++skipped;
574 423 : rv = NS_OK;
575 : }
576 :
577 1055 : if (NS_FAILED(rv))
578 : break;
579 : }
580 :
581 1023 : *aSkipped += skipped;
582 1023 : return rv;
583 : }
584 :
585 :
586 : nsresult
587 320 : nsRDFXMLSerializer::SerializeDescription(nsIOutputStream* aStream,
588 : nsIRDFResource* aResource)
589 : {
590 : nsresult rv;
591 :
592 320 : bool isTypedNode = false;
593 640 : nsCString typeQName;
594 :
595 640 : nsCOMPtr<nsIRDFNode> typeNode;
596 320 : mDataSource->GetTarget(aResource, kRDF_type, true, getter_AddRefs(typeNode));
597 320 : if (typeNode) {
598 0 : nsCOMPtr<nsIRDFResource> type = do_QueryInterface(typeNode, &rv);
599 0 : if (type) {
600 : // Try to get a namespace prefix. If none is available,
601 : // just treat the description as if it weren't a typed node
602 : // after all and emit rdf:type as a normal property. This
603 : // seems preferable to using a bogus (invented) prefix.
604 0 : isTypedNode = NS_SUCCEEDED(GetQName(type, typeQName));
605 : }
606 : }
607 :
608 640 : nsCAutoString uri;
609 320 : rv = aResource->GetValueUTF8(uri);
610 320 : if (NS_FAILED(rv)) return rv;
611 :
612 320 : rdf_MakeRelativeRef(mBaseURLSpec, uri);
613 320 : rdf_EscapeAttributeValue(uri);
614 :
615 : // Emit an open tag and the subject
616 320 : if (isTypedNode) {
617 0 : rv = rdf_BlockingWrite(aStream, NS_LITERAL_STRING(" <"));
618 0 : if (NS_FAILED(rv)) return rv;
619 : // Watch out for the default namespace!
620 0 : rv = rdf_BlockingWrite(aStream, typeQName);
621 0 : if (NS_FAILED(rv)) return rv;
622 : }
623 : else {
624 : rv = rdf_BlockingWrite(aStream, kRDFDescriptionOpen,
625 320 : sizeof(kRDFDescriptionOpen) - 1);
626 320 : if (NS_FAILED(rv)) return rv;
627 : }
628 320 : if (uri[0] == PRUnichar('#')) {
629 0 : uri.Cut(0, 1);
630 0 : rv = rdf_BlockingWrite(aStream, kIDAttr, sizeof(kIDAttr) - 1);
631 : }
632 : else {
633 320 : rv = rdf_BlockingWrite(aStream, kAboutAttr, sizeof(kAboutAttr) - 1);
634 : }
635 320 : if (NS_FAILED(rv)) return rv;
636 :
637 320 : uri.Append('"');
638 320 : rv = rdf_BlockingWrite(aStream, uri);
639 320 : if (NS_FAILED(rv)) return rv;
640 :
641 : // Any value that's a literal we can write out as an inline
642 : // attribute on the RDF:Description
643 640 : nsAutoTArray<nsIRDFResource*, 8> visited;
644 320 : PRInt32 skipped = 0;
645 :
646 640 : nsCOMPtr<nsISimpleEnumerator> arcs;
647 320 : mDataSource->ArcLabelsOut(aResource, getter_AddRefs(arcs));
648 :
649 320 : if (arcs) {
650 : // Don't re-serialize rdf:type later on
651 320 : if (isTypedNode)
652 0 : visited.AppendElement(kRDF_type);
653 :
654 616 : while (1) {
655 936 : bool hasMore = false;
656 936 : arcs->HasMoreElements(&hasMore);
657 936 : if (! hasMore)
658 : break;
659 :
660 1232 : nsCOMPtr<nsISupports> isupports;
661 616 : arcs->GetNext(getter_AddRefs(isupports));
662 :
663 1232 : nsCOMPtr<nsIRDFResource> property = do_QueryInterface(isupports);
664 616 : if (! property)
665 0 : continue;
666 :
667 : // Ignore properties that pertain to containers; we may be
668 : // called from SerializeContainer() if the container resource
669 : // has been assigned non-container properties.
670 616 : if (IsContainerProperty(property))
671 0 : continue;
672 :
673 : // Only serialize values for the property once.
674 616 : if (visited.Contains(property.get()))
675 0 : continue;
676 :
677 616 : visited.AppendElement(property.get());
678 :
679 1232 : SerializeProperty(aStream, aResource, property, true, &skipped);
680 : }
681 : }
682 :
683 320 : if (skipped) {
684 : // Close the RDF:Description tag.
685 206 : rv = rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING(">\n"));
686 206 : if (NS_FAILED(rv)) return rv;
687 :
688 : // Now write out resources (which might have their own
689 : // substructure) as children.
690 206 : mDataSource->ArcLabelsOut(aResource, getter_AddRefs(arcs));
691 :
692 206 : if (arcs) {
693 : // Forget that we've visited anything
694 206 : visited.Clear();
695 : // ... except for rdf:type
696 206 : if (isTypedNode)
697 0 : visited.AppendElement(kRDF_type);
698 :
699 407 : while (1) {
700 613 : bool hasMore = false;
701 613 : arcs->HasMoreElements(&hasMore);
702 613 : if (! hasMore)
703 : break;
704 :
705 814 : nsCOMPtr<nsISupports> isupports;
706 407 : arcs->GetNext(getter_AddRefs(isupports));
707 :
708 814 : nsCOMPtr<nsIRDFResource> property = do_QueryInterface(isupports);
709 407 : if (! property)
710 0 : continue;
711 :
712 : // Ignore properties that pertain to containers; we may be
713 : // called from SerializeContainer() if the container
714 : // resource has been assigned non-container properties.
715 407 : if (IsContainerProperty(property))
716 0 : continue;
717 :
718 : // have we already seen this property? If so, don't write it
719 : // out again; serialize property will write each instance.
720 407 : if (visited.Contains(property.get()))
721 0 : continue;
722 :
723 407 : visited.AppendElement(property.get());
724 :
725 814 : SerializeProperty(aStream, aResource, property, false, &skipped);
726 : }
727 : }
728 :
729 : // Emit a proper close-tag.
730 206 : if (isTypedNode) {
731 0 : rv = rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING(" </"));
732 0 : if (NS_FAILED(rv)) return rv;
733 : // Watch out for the default namespace!
734 0 : rdf_BlockingWrite(aStream, typeQName);
735 0 : if (NS_FAILED(rv)) return rv;
736 0 : rdf_BlockingWrite(aStream, ">\n", 2);
737 0 : if (NS_FAILED(rv)) return rv;
738 : }
739 : else {
740 : rv = rdf_BlockingWrite(aStream, kRDFDescriptionClose,
741 206 : sizeof(kRDFDescriptionClose) - 1);
742 206 : if (NS_FAILED(rv)) return rv;
743 : }
744 : }
745 : else {
746 : // If we saw _no_ child properties, then we can don't need a
747 : // close-tag.
748 114 : rv = rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING(" />\n"));
749 114 : if (NS_FAILED(rv)) return rv;
750 : }
751 :
752 320 : return NS_OK;
753 : }
754 :
755 : nsresult
756 93 : nsRDFXMLSerializer::SerializeMember(nsIOutputStream* aStream,
757 : nsIRDFResource* aContainer,
758 : nsIRDFNode* aMember)
759 : {
760 : // If it's a resource, then output a "<RDF:li RDF:resource=... />"
761 : // tag, because we'll be dumping the resource separately. (We
762 : // iterate thru all the resources in the datasource,
763 : // remember?) Otherwise, output the literal value.
764 :
765 186 : nsCOMPtr<nsIRDFResource> resource;
766 186 : nsCOMPtr<nsIRDFLiteral> literal;
767 186 : nsCOMPtr<nsIRDFInt> number;
768 186 : nsCOMPtr<nsIRDFDate> date;
769 :
770 : static const char kRDFLIOpen[] = " <RDF:li";
771 : nsresult rv = rdf_BlockingWrite(aStream, kRDFLIOpen,
772 93 : sizeof(kRDFLIOpen) - 1);
773 93 : if (NS_FAILED(rv)) return rv;
774 :
775 93 : if ((resource = do_QueryInterface(aMember)) != nsnull) {
776 186 : nsCAutoString uri;
777 93 : resource->GetValueUTF8(uri);
778 :
779 93 : rdf_MakeRelativeRef(mBaseURLSpec, uri);
780 93 : rdf_EscapeAttributeValue(uri);
781 :
782 : rv = rdf_BlockingWrite(aStream, kRDFResource1,
783 93 : sizeof(kRDFResource1) - 1);
784 93 : if (NS_FAILED(rv)) return rv;
785 93 : rv = rdf_BlockingWrite(aStream, uri);
786 93 : if (NS_FAILED(rv)) return rv;
787 : rv = rdf_BlockingWrite(aStream, kRDFResource2,
788 93 : sizeof(kRDFResource2) - 1);
789 93 : if (NS_FAILED(rv)) return rv;
790 :
791 93 : goto no_close_tag;
792 : }
793 0 : else if ((literal = do_QueryInterface(aMember)) != nsnull) {
794 : const PRUnichar *value;
795 0 : literal->GetValueConst(&value);
796 : static const char kRDFLIOpenGT[] = ">";
797 : // close the '<RDF:LI' before adding the literal
798 : rv = rdf_BlockingWrite(aStream, kRDFLIOpenGT,
799 0 : sizeof(kRDFLIOpenGT) - 1);
800 0 : if (NS_FAILED(rv)) return rv;
801 :
802 0 : NS_ConvertUTF16toUTF8 s(value);
803 0 : rdf_EscapeAmpersandsAndAngleBrackets(s);
804 :
805 0 : rv = rdf_BlockingWrite(aStream, s);
806 0 : if (NS_FAILED(rv)) return rv;
807 : }
808 0 : else if ((number = do_QueryInterface(aMember)) != nsnull) {
809 : PRInt32 value;
810 0 : number->GetValue(&value);
811 :
812 0 : nsCAutoString n;
813 0 : n.AppendInt(value);
814 :
815 : rv = rdf_BlockingWrite(aStream, kRDFParseTypeInteger,
816 0 : sizeof(kRDFParseTypeInteger) - 1);
817 0 : if (NS_FAILED(rv)) return rv;
818 0 : rv = rdf_BlockingWrite(aStream, n);
819 0 : if (NS_FAILED(rv)) return rv;
820 : }
821 0 : else if ((date = do_QueryInterface(aMember)) != nsnull) {
822 : PRTime value;
823 0 : date->GetValue(&value);
824 :
825 0 : nsCAutoString s;
826 0 : rdf_FormatDate(value, s);
827 :
828 : rv = rdf_BlockingWrite(aStream, kRDFParseTypeDate,
829 0 : sizeof(kRDFParseTypeDate) - 1);
830 0 : if (NS_FAILED(rv)) return rv;
831 0 : rv = rdf_BlockingWrite(aStream, s);
832 0 : if (NS_FAILED(rv)) return rv;
833 : }
834 : else {
835 : // XXX it doesn't support nsIRDFResource _or_ nsIRDFLiteral???
836 : // We should serialize nsIRDFInt, nsIRDFDate, etc...
837 0 : NS_WARNING("unknown RDF node type");
838 :
839 0 : rv = rdf_BlockingWrite(aStream, kRDFUnknown, sizeof(kRDFUnknown) - 1);
840 0 : if (NS_FAILED(rv)) return rv;
841 : }
842 :
843 : {
844 : static const char kRDFLIClose[] = "</RDF:li>\n";
845 0 : rv = rdf_BlockingWrite(aStream, kRDFLIClose, sizeof(kRDFLIClose) - 1);
846 0 : if (NS_FAILED(rv)) return rv;
847 : }
848 :
849 : no_close_tag:
850 93 : return NS_OK;
851 : }
852 :
853 :
854 : nsresult
855 29 : nsRDFXMLSerializer::SerializeContainer(nsIOutputStream* aStream,
856 : nsIRDFResource* aContainer)
857 : {
858 : nsresult rv;
859 58 : nsCAutoString tag;
860 :
861 : // Decide if it's a sequence, bag, or alternation, and print the
862 : // appropriate tag-open sequence
863 :
864 29 : if (IsA(mDataSource, aContainer, kRDF_Bag)) {
865 0 : tag.AssignLiteral("RDF:Bag");
866 : }
867 29 : else if (IsA(mDataSource, aContainer, kRDF_Seq)) {
868 29 : tag.AssignLiteral("RDF:Seq");
869 : }
870 0 : else if (IsA(mDataSource, aContainer, kRDF_Alt)) {
871 0 : tag.AssignLiteral("RDF:Alt");
872 : }
873 : else {
874 0 : NS_ASSERTION(false, "huh? this is _not_ a container.");
875 0 : return NS_ERROR_UNEXPECTED;
876 : }
877 :
878 29 : rv = rdf_BlockingWrite(aStream, " <", 3);
879 29 : if (NS_FAILED(rv)) return rv;
880 29 : rv = rdf_BlockingWrite(aStream, tag);
881 29 : if (NS_FAILED(rv)) return rv;
882 :
883 :
884 : // Unfortunately, we always need to print out the identity of the
885 : // resource, even if was constructed "anonymously". We need to do
886 : // this because we never really know who else might be referring
887 : // to it...
888 :
889 58 : nsCAutoString uri;
890 29 : if (NS_SUCCEEDED(aContainer->GetValueUTF8(uri))) {
891 29 : rdf_MakeRelativeRef(mBaseURLSpec, uri);
892 :
893 29 : rdf_EscapeAttributeValue(uri);
894 :
895 29 : if (uri.First() == '#') {
896 : // Okay, it's actually identified as an element in the
897 : // current document, not trying to decorate some absolute
898 : // URI. We can use the 'ID=' attribute...
899 :
900 0 : uri.Cut(0, 1); // chop the '#'
901 0 : rv = rdf_BlockingWrite(aStream, kIDAttr, sizeof(kIDAttr) - 1);
902 0 : if (NS_FAILED(rv)) return rv;
903 : }
904 : else {
905 : // We need to cheat and spit out an illegal 'about=' on
906 : // the sequence.
907 : rv = rdf_BlockingWrite(aStream, kAboutAttr,
908 29 : sizeof(kAboutAttr) - 1);
909 29 : if (NS_FAILED(rv)) return rv;
910 : }
911 :
912 29 : rv = rdf_BlockingWrite(aStream, uri);
913 29 : if (NS_FAILED(rv)) return rv;
914 29 : rv = rdf_BlockingWrite(aStream, "\"", 1);
915 29 : if (NS_FAILED(rv)) return rv;
916 : }
917 :
918 29 : rv = rdf_BlockingWrite(aStream, ">\n", 2);
919 29 : if (NS_FAILED(rv)) return rv;
920 :
921 : // First iterate through each of the ordinal elements (the RDF/XML
922 : // syntax doesn't allow us to place properties on RDF container
923 : // elements).
924 58 : nsCOMPtr<nsISimpleEnumerator> elements;
925 29 : rv = NS_NewContainerEnumerator(mDataSource, aContainer, getter_AddRefs(elements));
926 :
927 29 : if (NS_SUCCEEDED(rv)) {
928 93 : while (1) {
929 : bool hasMore;
930 122 : rv = elements->HasMoreElements(&hasMore);
931 122 : if (NS_FAILED(rv)) break;
932 :
933 122 : if (! hasMore)
934 29 : break;
935 :
936 186 : nsCOMPtr<nsISupports> isupports;
937 93 : elements->GetNext(getter_AddRefs(isupports));
938 :
939 186 : nsCOMPtr<nsIRDFNode> element = do_QueryInterface(isupports);
940 93 : NS_ASSERTION(element != nsnull, "not an nsIRDFNode");
941 93 : if (! element)
942 0 : continue;
943 :
944 186 : SerializeMember(aStream, aContainer, element);
945 : }
946 : }
947 :
948 : // close the container tag
949 29 : rv = rdf_BlockingWrite(aStream, " </", 4);
950 29 : if (NS_FAILED(rv)) return rv;
951 29 : tag.Append(">\n", 2);
952 29 : rv = rdf_BlockingWrite(aStream, tag);
953 29 : if (NS_FAILED(rv)) return rv;
954 :
955 : // Now, we iterate through _all_ of the arcs, in case someone has
956 : // applied properties to the bag itself. These'll be placed in a
957 : // separate RDF:Description element.
958 58 : nsCOMPtr<nsISimpleEnumerator> arcs;
959 29 : mDataSource->ArcLabelsOut(aContainer, getter_AddRefs(arcs));
960 :
961 29 : bool wroteDescription = false;
962 209 : while (! wroteDescription) {
963 180 : bool hasMore = false;
964 180 : rv = arcs->HasMoreElements(&hasMore);
965 180 : if (NS_FAILED(rv)) break;
966 :
967 180 : if (! hasMore)
968 29 : break;
969 :
970 : nsIRDFResource* property;
971 151 : rv = arcs->GetNext((nsISupports**) &property);
972 151 : if (NS_FAILED(rv)) break;
973 :
974 : // If it's a membership property, then output a "LI"
975 : // tag. Otherwise, output a property.
976 151 : if (! IsContainerProperty(property)) {
977 0 : rv = SerializeDescription(aStream, aContainer);
978 0 : wroteDescription = true;
979 : }
980 :
981 151 : NS_RELEASE(property);
982 151 : if (NS_FAILED(rv))
983 0 : break;
984 : }
985 :
986 29 : return NS_OK;
987 : }
988 :
989 :
990 : nsresult
991 19 : nsRDFXMLSerializer::SerializePrologue(nsIOutputStream* aStream)
992 : {
993 : static const char kXMLVersion[] = "<?xml version=\"1.0\"?>\n";
994 :
995 : nsresult rv;
996 19 : rv = rdf_BlockingWrite(aStream, kXMLVersion, sizeof(kXMLVersion) - 1);
997 19 : if (NS_FAILED(rv)) return rv;
998 :
999 : // global name space declarations
1000 19 : rv = rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING("<RDF:RDF "));
1001 19 : if (NS_FAILED(rv)) return rv;
1002 :
1003 19 : nsNameSpaceMap::const_iterator first = mNameSpaces.first();
1004 19 : nsNameSpaceMap::const_iterator last = mNameSpaces.last();
1005 57 : for (nsNameSpaceMap::const_iterator entry = first; entry != last; ++entry) {
1006 38 : if (entry != first) {
1007 19 : rv = rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING("\n "));
1008 19 : if (NS_FAILED(rv)) return rv;
1009 : }
1010 38 : rv = rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING("xmlns"));
1011 38 : if (NS_FAILED(rv)) return rv;
1012 :
1013 38 : if (entry->mPrefix) {
1014 38 : rv = rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING(":"));
1015 38 : if (NS_FAILED(rv)) return rv;
1016 76 : nsCAutoString prefix;
1017 38 : entry->mPrefix->ToUTF8String(prefix);
1018 38 : rv = rdf_BlockingWrite(aStream, prefix);
1019 38 : if (NS_FAILED(rv)) return rv;
1020 : }
1021 :
1022 38 : rv = rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING("=\""));
1023 38 : if (NS_FAILED(rv)) return rv;
1024 76 : nsCAutoString uri(entry->mURI);
1025 38 : rdf_EscapeAttributeValue(uri);
1026 38 : rv = rdf_BlockingWrite(aStream, uri);
1027 38 : if (NS_FAILED(rv)) return rv;
1028 38 : rv = rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING("\""));
1029 38 : if (NS_FAILED(rv)) return rv;
1030 : }
1031 :
1032 19 : return rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING(">\n"));
1033 : }
1034 :
1035 :
1036 : nsresult
1037 19 : nsRDFXMLSerializer::SerializeEpilogue(nsIOutputStream* aStream)
1038 : {
1039 19 : return rdf_BlockingWrite(aStream, NS_LITERAL_CSTRING("</RDF:RDF>\n"));
1040 : }
1041 :
1042 : class QNameCollector : public rdfITripleVisitor {
1043 : public:
1044 : NS_DECL_ISUPPORTS
1045 : NS_DECL_RDFITRIPLEVISITOR
1046 19 : QNameCollector(nsRDFXMLSerializer* aParent)
1047 19 : : mParent(aParent){}
1048 : private:
1049 : nsRDFXMLSerializer* mParent;
1050 : };
1051 :
1052 114 : NS_IMPL_ISUPPORTS1(QNameCollector, rdfITripleVisitor)
1053 : nsresult
1054 783 : QNameCollector::Visit(nsIRDFNode* aSubject, nsIRDFResource* aPredicate,
1055 : nsIRDFNode* aObject, bool aTruthValue)
1056 : {
1057 783 : if (aPredicate == mParent->kRDF_type) {
1058 : // try to get a type QName for aObject, should be a resource
1059 0 : nsCOMPtr<nsIRDFResource> resType = do_QueryInterface(aObject);
1060 0 : if (!resType) {
1061 : // ignore error
1062 0 : return NS_OK;
1063 : }
1064 0 : if (mParent->mQNames.Get(resType, nsnull)) {
1065 0 : return NS_OK;
1066 : }
1067 0 : mParent->RegisterQName(resType);
1068 0 : return NS_OK;
1069 : }
1070 :
1071 783 : if (mParent->mQNames.Get(aPredicate, nsnull)) {
1072 427 : return NS_OK;
1073 : }
1074 356 : if (aPredicate == mParent->kRDF_instanceOf ||
1075 : aPredicate == mParent->kRDF_nextVal)
1076 58 : return NS_OK;
1077 298 : bool isOrdinal = false;
1078 298 : mParent->gRDFC->IsOrdinalProperty(aPredicate, &isOrdinal);
1079 298 : if (isOrdinal)
1080 93 : return NS_OK;
1081 :
1082 205 : mParent->RegisterQName(aPredicate);
1083 :
1084 205 : return NS_OK;
1085 : }
1086 :
1087 : nsresult
1088 19 : nsRDFXMLSerializer::CollectNamespaces()
1089 : {
1090 : // Iterate over all Triples to get namespaces for subject resource types
1091 : // and Predicates and cache all the QNames we want to use.
1092 : nsCOMPtr<rdfITripleVisitor> collector =
1093 38 : new QNameCollector(this);
1094 38 : nsCOMPtr<rdfIDataSource> ds = do_QueryInterface(mDataSource); // XXX API
1095 19 : NS_ENSURE_TRUE(collector && ds, NS_ERROR_FAILURE);
1096 19 : return ds->VisitAllTriples(collector);
1097 : }
1098 :
1099 : //----------------------------------------------------------------------
1100 :
1101 : NS_IMETHODIMP
1102 19 : nsRDFXMLSerializer::Serialize(nsIOutputStream* aStream)
1103 : {
1104 : nsresult rv;
1105 :
1106 19 : rv = CollectNamespaces();
1107 19 : if (NS_FAILED(rv)) return rv;
1108 :
1109 38 : nsCOMPtr<nsISimpleEnumerator> resources;
1110 19 : rv = mDataSource->GetAllResources(getter_AddRefs(resources));
1111 19 : if (NS_FAILED(rv)) return rv;
1112 :
1113 19 : rv = SerializePrologue(aStream);
1114 19 : if (NS_FAILED(rv))
1115 0 : return rv;
1116 :
1117 349 : while (1) {
1118 368 : bool hasMore = false;
1119 368 : resources->HasMoreElements(&hasMore);
1120 368 : if (! hasMore)
1121 19 : break;
1122 :
1123 698 : nsCOMPtr<nsISupports> isupports;
1124 349 : resources->GetNext(getter_AddRefs(isupports));
1125 :
1126 698 : nsCOMPtr<nsIRDFResource> resource = do_QueryInterface(isupports);
1127 349 : if (! resource)
1128 0 : continue;
1129 :
1130 1018 : if (IsA(mDataSource, resource, kRDF_Bag) ||
1131 349 : IsA(mDataSource, resource, kRDF_Seq) ||
1132 320 : IsA(mDataSource, resource, kRDF_Alt)) {
1133 29 : rv = SerializeContainer(aStream, resource);
1134 : }
1135 : else {
1136 320 : rv = SerializeDescription(aStream, resource);
1137 : }
1138 :
1139 349 : if (NS_FAILED(rv))
1140 : break;
1141 : }
1142 :
1143 19 : rv = SerializeEpilogue(aStream);
1144 :
1145 19 : return rv;
1146 : }
1147 :
1148 :
1149 : bool
1150 1076 : nsRDFXMLSerializer::IsA(nsIRDFDataSource* aDataSource, nsIRDFResource* aResource, nsIRDFResource* aType)
1151 : {
1152 : nsresult rv;
1153 :
1154 : bool result;
1155 1076 : rv = aDataSource->HasAssertion(aResource, kRDF_instanceOf, aType, true, &result);
1156 1076 : if (NS_FAILED(rv)) return false;
1157 :
1158 1076 : return result;
1159 : }
|