From 60fd366f395a789702dd99b790277a0853b979f8 Mon Sep 17 00:00:00 2001 From: mdesalvo Date: Sun, 6 Oct 2024 17:19:31 +0200 Subject: [PATCH] Restore code for parseType="Collection" (stabilized) --- RDFSharp.Test/Model/Serializers/RDFXmlTest.cs | 100 +++++++++++++++--- RDFSharp/Model/Serializers/RDFXml.cs | 71 +++++++++++++ 2 files changed, 158 insertions(+), 13 deletions(-) diff --git a/RDFSharp.Test/Model/Serializers/RDFXmlTest.cs b/RDFSharp.Test/Model/Serializers/RDFXmlTest.cs index 209b1f81..dc539236 100644 --- a/RDFSharp.Test/Model/Serializers/RDFXmlTest.cs +++ b/RDFSharp.Test/Model/Serializers/RDFXmlTest.cs @@ -1,4 +1,4 @@ -/* +/* Copyright 2012-2024 Marco De Salvo Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,6 +19,7 @@ limitations under the License. using System; using System.IO; using System.Linq; +using System.Text.RegularExpressions; namespace RDFSharp.Test.Model { @@ -179,6 +180,21 @@ public void ShouldSerializeGraphWithSPBTripleHavingAltContainerOfLiteralsAsObjec Assert.IsTrue(fileContent.Equals($"{XmlHeader}{Environment.NewLine}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",6}{Environment.NewLine}{" ",8}lit1{Environment.NewLine}{" ",6}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",2}{Environment.NewLine}")); } + [TestMethod] + public void ShouldSerializeGraphWithSPBTripleHavingBagContainerOfLiteralsAsObject() + { + RDFContainer cont = new RDFContainer(RDFModelEnums.RDFContainerTypes.Bag, RDFModelEnums.RDFItemTypes.Literal); + cont.AddItem(new RDFPlainLiteral("lit1")); + RDFGraph graph = new RDFGraph(); + graph.AddTriple(new RDFTriple(new RDFResource("http://subj/"), new RDFResource("http://pred/pred/"), cont.ReificationSubject)); + graph.AddContainer(cont); + RDFXml.Serialize(graph, Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithSPBTripleHavingBagContainerOfLiteralsAsObject.rdf")); + + Assert.IsTrue(File.Exists(Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithSPBTripleHavingBagContainerOfLiteralsAsObject.rdf"))); + string fileContent = File.ReadAllText(Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithSPBTripleHavingBagContainerOfLiteralsAsObject.rdf")); + Assert.IsTrue(fileContent.Equals($"{XmlHeader}{Environment.NewLine}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",6}{Environment.NewLine}{" ",8}lit1{Environment.NewLine}{" ",6}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",2}{Environment.NewLine}")); + } + [TestMethod] public void ShouldSerializeGraphWithSPBTripleHavingSeqContainerOfLiteralsAsObject() { @@ -199,7 +215,7 @@ public void ShouldSerializeGraphWithSPBTripleHavingCollectionOfResourcesAsObject { RDFCollection coll = new RDFCollection(RDFModelEnums.RDFItemTypes.Resource); coll.AddItem(new RDFResource("http://item1/")); - coll.ReificationSubject = new RDFResource("http://coll/"); + coll.AddItem(new RDFResource("bnode:item2")); RDFGraph graph = new RDFGraph(); graph.AddTriple(new RDFTriple(new RDFResource("http://subj/"), new RDFResource("http://pred/pred/"), coll.ReificationSubject)); graph.AddCollection(coll); @@ -207,7 +223,7 @@ public void ShouldSerializeGraphWithSPBTripleHavingCollectionOfResourcesAsObject Assert.IsTrue(File.Exists(Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithSPBTripleHavingCollectionOfResourcesAsObject.rdf"))); string fileContent = File.ReadAllText(Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithSPBTripleHavingCollectionOfResourcesAsObject.rdf")); - Assert.IsTrue(fileContent.Equals($"{XmlHeader}{Environment.NewLine}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",2}{Environment.NewLine}")); + Assert.IsTrue(fileContent.Equals($"{XmlHeader}{Environment.NewLine}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",6}{Environment.NewLine}{" ",6}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",2}{Environment.NewLine}")); } [TestMethod] @@ -242,6 +258,16 @@ public void ShouldSerializeGraphWithSPBTripleHavingCollectionOfLanguagedLiterals Assert.IsTrue(fileContent.Equals($"{XmlHeader}{Environment.NewLine}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",4}lit1{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",2}{Environment.NewLine}")); } + [TestMethod] + public void ShouldThrowExceptionOnSerializingGraphWithSPOTripleBecauseBadFormedCollectionAsObject() + { + RDFGraph graph = new RDFGraph(); + graph.AddTriple(new RDFTriple(new RDFResource("http://subj/"), new RDFResource("http://pred/pred"), new RDFResource("bnode:12345"))); + graph.AddTriple(new RDFTriple(new RDFResource("bnode:12345"), RDFVocabulary.RDF.TYPE, RDFVocabulary.RDF.LIST)); + graph.AddTriple(new RDFTriple(new RDFResource("bnode:12345"), RDFVocabulary.RDF.FIRST, new RDFResource("http://item1/"))); + Assert.ThrowsException(() => RDFXml.Serialize(graph, Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldThrowExceptionOnSerializingGraphWithSPOTripleBecauseBadFormedCollectionAsObject.rdf"))); + } + [TestMethod] public void ShouldSerializeGraphWithSPBTripleHavingMixedCollectionAsObject() { @@ -258,7 +284,10 @@ public void ShouldSerializeGraphWithSPBTripleHavingMixedCollectionAsObject() Assert.IsTrue(File.Exists(Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithSPBTripleHavingMixedCollectionAsObject.rdf"))); string fileContent = File.ReadAllText(Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithSPBTripleHavingMixedCollectionAsObject.rdf")); Assert.IsNotNull(fileContent); - Assert.IsTrue(!fileContent.Contains("rdf:parseType")); + + string adjustedFileContent = Regex.Replace(fileContent, "rdf:nodeID=\"(.)+\"", "rdf:nodeID=\"12345\""); + Assert.IsNotNull(adjustedFileContent); + Assert.IsTrue(adjustedFileContent.Equals($"{XmlHeader}{Environment.NewLine}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",4}item1{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",6}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",2}{Environment.NewLine}")); } [TestMethod] @@ -648,25 +677,29 @@ public void ShouldSerializeGraphWithFloatingCollectionOfResources() { RDFCollection coll = new RDFCollection(RDFModelEnums.RDFItemTypes.Resource); coll.AddItem(new RDFResource("http://item1/")); + coll.AddItem(new RDFResource("http://item2/")); + coll.AddItem(new RDFResource("http://item3/")); coll.ReificationSubject = new RDFResource("bnode:12345"); RDFXml.Serialize(coll.ReifyCollection(), Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithFloatingCollectionOfResources.rdf")); Assert.IsTrue(File.Exists(Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithFloatingCollectionOfResources.rdf"))); string fileContent = File.ReadAllText(Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithFloatingCollectionOfResources.rdf")); - Assert.IsTrue(fileContent.Equals($"{XmlHeader}{Environment.NewLine}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",2}{Environment.NewLine}")); + Assert.IsTrue(fileContent.Equals($"{XmlHeader}{Environment.NewLine}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",6}{Environment.NewLine}{" ",6}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",2}{Environment.NewLine}")); } [TestMethod] - public void ShouldSerializeGraphWithFloatingCollectionOfLiterals() + public void ShouldSerializeGraphWithFloatingCollectionOfBlankResources() { - RDFCollection coll = new RDFCollection(RDFModelEnums.RDFItemTypes.Literal); - coll.AddItem(new RDFPlainLiteral("item1","en--rtl")); + RDFCollection coll = new RDFCollection(RDFModelEnums.RDFItemTypes.Resource); + coll.AddItem(new RDFResource("bnode:item1")); + coll.AddItem(new RDFResource("bnode:item2")); + coll.AddItem(new RDFResource("bnode:item3")); coll.ReificationSubject = new RDFResource("bnode:12345"); - RDFXml.Serialize(coll.ReifyCollection(), Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithFloatingCollectionOfLiterals.rdf")); + RDFXml.Serialize(coll.ReifyCollection(), Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithFloatingCollectionOfBlankResources.rdf")); - Assert.IsTrue(File.Exists(Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithFloatingCollectionOfLiterals.rdf"))); - string fileContent = File.ReadAllText(Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithFloatingCollectionOfLiterals.rdf")); - Assert.IsTrue(fileContent.Equals($"{XmlHeader}{Environment.NewLine}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",4}item1{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",2}{Environment.NewLine}")); + Assert.IsTrue(File.Exists(Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithFloatingCollectionOfBlankResources.rdf"))); + string fileContent = File.ReadAllText(Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithFloatingCollectionOfBlankResources.rdf")); + Assert.IsTrue(fileContent.Equals($"{XmlHeader}{Environment.NewLine}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",6}{Environment.NewLine}{" ",6}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",2}{Environment.NewLine}")); } [TestMethod] @@ -675,10 +708,14 @@ public void ShouldSerializeGraphWithBothFloatingAndNonFloatingCollectionsOfResou RDFGraph graph = new RDFGraph(); RDFCollection coll = new RDFCollection(RDFModelEnums.RDFItemTypes.Resource); coll.AddItem(new RDFResource("http://item1/")); + coll.AddItem(new RDFResource("http://item2/")); + coll.AddItem(new RDFResource("http://item3/")); coll.ReificationSubject = new RDFResource("bnode:12345"); graph.AddCollection(coll); RDFCollection coll2 = new RDFCollection(RDFModelEnums.RDFItemTypes.Resource); coll2.AddItem(new RDFResource("http://item1/")); + coll2.AddItem(new RDFResource("http://item2/")); + coll2.AddItem(new RDFResource("http://item3/")); coll2.ReificationSubject = new RDFResource("bnode:54321"); graph.AddCollection(coll2); graph.AddTriple(new RDFTriple(new RDFResource("http://subj/"), new RDFResource("http://pred/pred"), coll2.ReificationSubject)); @@ -686,7 +723,44 @@ public void ShouldSerializeGraphWithBothFloatingAndNonFloatingCollectionsOfResou Assert.IsTrue(File.Exists(Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithBothFloatingAndNonFloatingCollectionsOfResources.rdf"))); string fileContent = File.ReadAllText(Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithBothFloatingAndNonFloatingCollectionsOfResources.rdf")); - Assert.IsTrue(fileContent.Equals($"{XmlHeader}{Environment.NewLine}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",2}{Environment.NewLine}")); + Assert.IsTrue(fileContent.Equals($"{XmlHeader}{Environment.NewLine}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",6}{Environment.NewLine}{" ",6}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",6}{Environment.NewLine}{" ",6}{Environment.NewLine}{" ",6}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",2}{Environment.NewLine}")); + } + + [TestMethod] + public void ShouldSerializeGraphWithBothFloatingAndNonFloatingCollectionsOfBlankResources() + { + RDFGraph graph = new RDFGraph(); + RDFCollection coll = new RDFCollection(RDFModelEnums.RDFItemTypes.Resource); + coll.AddItem(new RDFResource("bnode:item1")); + coll.AddItem(new RDFResource("bnode:item2")); + coll.AddItem(new RDFResource("bnode:item3")); + coll.ReificationSubject = new RDFResource("bnode:12345"); + graph.AddCollection(coll); + RDFCollection coll2 = new RDFCollection(RDFModelEnums.RDFItemTypes.Resource); + coll2.AddItem(new RDFResource("bnode:item1")); + coll2.AddItem(new RDFResource("bnode:item2")); + coll2.AddItem(new RDFResource("bnode:item3")); + coll2.ReificationSubject = new RDFResource("bnode:54321"); + graph.AddCollection(coll2); + graph.AddTriple(new RDFTriple(new RDFResource("http://subj/"), new RDFResource("http://pred/pred"), coll2.ReificationSubject)); + RDFXml.Serialize(graph, Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithBothFloatingAndNonFloatingCollectionsOfBlankResources.rdf")); + + Assert.IsTrue(File.Exists(Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithBothFloatingAndNonFloatingCollectionsOfBlankResources.rdf"))); + string fileContent = File.ReadAllText(Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithBothFloatingAndNonFloatingCollectionsOfBlankResources.rdf")); + Assert.IsTrue(fileContent.Equals($"{XmlHeader}{Environment.NewLine}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",6}{Environment.NewLine}{" ",6}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",6}{Environment.NewLine}{" ",6}{Environment.NewLine}{" ",6}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",2}{Environment.NewLine}")); + } + + [TestMethod] + public void ShouldSerializeGraphWithFloatingCollectionOfLiterals() + { + RDFCollection coll = new RDFCollection(RDFModelEnums.RDFItemTypes.Literal); + coll.AddItem(new RDFPlainLiteral("item1","en--rtl")); + coll.ReificationSubject = new RDFResource("bnode:12345"); + RDFXml.Serialize(coll.ReifyCollection(), Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithFloatingCollectionOfLiterals.rdf")); + + Assert.IsTrue(File.Exists(Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithFloatingCollectionOfLiterals.rdf"))); + string fileContent = File.ReadAllText(Path.Combine(Environment.CurrentDirectory, $"RDFXmlTest_ShouldSerializeGraphWithFloatingCollectionOfLiterals.rdf")); + Assert.IsTrue(fileContent.Equals($"{XmlHeader}{Environment.NewLine}{Environment.NewLine}{" ",2}{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",4}item1{Environment.NewLine}{" ",4}{Environment.NewLine}{" ",2}{Environment.NewLine}")); } [TestMethod] diff --git a/RDFSharp/Model/Serializers/RDFXml.cs b/RDFSharp/Model/Serializers/RDFXml.cs index 1eea7914..c51bd985 100644 --- a/RDFSharp/Model/Serializers/RDFXml.cs +++ b/RDFSharp/Model/Serializers/RDFXml.cs @@ -103,6 +103,20 @@ internal static void Serialize(RDFGraph graph, Stream outputStream) RDFModelEnums.RDFContainerTypes.Seq, IsFloatingContainer = !graph.IndexedTriples.Any(v => v.Value.ObjectID.Equals(t.Subject.PatternMemberID)) }).ToList(); + + //Fetch data describing collections of the graph + var collections = rdfType.SelectTriplesByObject(RDFVocabulary.RDF.LIST) + .Select(t => new + { + CollectionUri = (RDFResource)t.Subject, + CollectionValue = rdfFirst.SelectTriplesBySubject((RDFResource)t.Subject) + .FirstOrDefault()?.Object, + CollectionNext = rdfRest.SelectTriplesBySubject((RDFResource)t.Subject) + .FirstOrDefault()?.Object, + IsFloatingCollection = !graph.IndexedTriples.Any(v => v.Value.ObjectID.Equals(t.Subject.PatternMemberID)), + HasAllResourceItems = RDFModelUtilities.DeserializeCollectionFromGraph(graph, (RDFResource)t.Subject, RDFModelEnums.RDFTripleFlavors.SPO, true) + .Items.TrueForAll(collItem => collItem is RDFResource) + }).ToList(); #endregion #region linq @@ -122,6 +136,7 @@ internal static void Serialize(RDFGraph graph, Stream outputStream) string subj = triplesGroup.Key; long subjHash = RDFModelUtilities.CreateHash(subj); var subjContainer = containers.Find(x => x.ContainerUri.PatternMemberID == subjHash); + var subjCollection = collections.Find(x => x.CollectionUri.PatternMemberID == subjHash); //It is a container subject and it is not floating => add it to the containersXML pool if (subjContainer != null && !subjContainer.IsFloatingContainer) @@ -140,6 +155,13 @@ internal static void Serialize(RDFGraph graph, Stream outputStream) } containersXML.Add(subjHash, subjNode); } + + //It is a collection subject of resources and it is not floating => do not append its triples because + //we will reconstruct the collection later and append it as "rdf:parseType=Collection" + else if (subjCollection != null + && !subjCollection.IsFloatingCollection + && subjCollection.HasAllResourceItems) + continue; //It is a traditional subject else @@ -198,11 +220,60 @@ internal static void Serialize(RDFGraph graph, Stream outputStream) if (triple.TripleFlavor == RDFModelEnums.RDFTripleFlavors.SPO) { var containerObj = containers.Find(x => x.ContainerUri.Equals(triple.Object)); + var collectionObj = collections.Find(x => x.CollectionUri.Equals(triple.Object)); //Object is a container subject and it is not floating => append its node saved in containersXML if (containerObj != null && !containerObj.IsFloatingContainer) predNode.AppendChild(containersXML[containerObj.ContainerUri.PatternMemberID]); + //Object is a collection subject of resources and it is not floating => append its "rdf:parseType=Collection" representation + else if (collectionObj != null + && !collectionObj.IsFloatingCollection + && collectionObj.HasAllResourceItems) + { + //Append "rdf:parseType=Collection" attribute + XmlAttribute rdfParseType = rdfDoc.CreateAttribute("rdf:parseType", RDFVocabulary.RDF.BASE_URI); + XmlText rdfParseTypeText = rdfDoc.CreateTextNode("Collection"); + rdfParseType.AppendChild(rdfParseTypeText); + predNode.Attributes.Append(rdfParseType); + + //Append "rdf:parseType=Collection" elements + bool nilFound = false; + RDFResource currentCollItem = (RDFResource)triple.Object; + List collElements = new List(); + XmlNode collElementToAppend = null; + XmlAttribute collElementAttr = null; + XmlText collElementAttrText = null; + while (!nilFound) + { + var collElement = collections.Find(x => x.CollectionUri.Equals(currentCollItem)); + if (collElement == null || collElement.CollectionValue == null || collElement.CollectionNext == null) + throw new RDFModelException(string.Format("Collection having '{0}' as subject is not well-formed. Please check presence of its 'rdf:type/rdf:first/rdf:rest' triples.", currentCollItem)); + + collElementToAppend = rdfDoc.CreateNode(XmlNodeType.Element, "rdf:Description", RDFVocabulary.RDF.BASE_URI); + if (collElement.CollectionValue.ToString().StartsWith("bnode:", StringComparison.Ordinal)) + { + collElementAttrText = rdfDoc.CreateTextNode(collElement.CollectionValue.ToString().Replace("bnode:", string.Empty)); + collElementAttr = rdfDoc.CreateAttribute("rdf:nodeID", RDFVocabulary.RDF.BASE_URI); + } + else + { + collElementAttrText = rdfDoc.CreateTextNode(collElement.CollectionValue.ToString()); + collElementAttr = rdfDoc.CreateAttribute("rdf:about", RDFVocabulary.RDF.BASE_URI); + } + collElementAttr.AppendChild(collElementAttrText); + collElementToAppend.Attributes.Append(collElementAttr); + collElements.Add(collElementToAppend); + + //Verify if this is the last element of the collection (pointing to next="rdf:nil") + if (collElement.CollectionNext.Equals(RDFVocabulary.RDF.NIL)) + nilFound = true; + else + currentCollItem = (RDFResource)collElement.CollectionNext; + } + collElements.ForEach(c => predNode.AppendChild(c)); + } + //Object is traditional else {