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