private IRdfXmlEvent GetElement() { // Generate Element Event ElementEvent el = new ElementEvent(_reader.Name, GetBaseUri(), _reader.Value, GetPosition()); _requireEndElement = _reader.IsEmptyElement; // Read Attribute Events if (_reader.HasAttributes) { for (int i = 0; i < _reader.AttributeCount; i++) { IRdfXmlEvent attr = GetNextAttribute(); if (attr is AttributeEvent) { el.Attributes.Add((AttributeEvent)attr); } else if (attr is NamespaceAttributeEvent) { el.NamespaceAttributes.Add((NamespaceAttributeEvent)attr); } else if (attr is LanguageAttributeEvent) { el.Language = ((LanguageAttributeEvent)attr).Language; } else if (attr is ParseTypeAttributeEvent) { el.ParseType = ((ParseTypeAttributeEvent)attr).ParseType; el.Attributes.Add(new AttributeEvent(_reader.Name, _reader.Value, _reader.Value, GetPosition())); } else if (attr is XmlBaseAttributeEvent) { el.BaseUri = ((XmlBaseAttributeEvent)attr).BaseUri; _currentBaseUri = el.BaseUri; } } } // Validate generated Attributes for Namespace Confusion and URIRef encoding foreach (AttributeEvent a in el.Attributes) { // Namespace Confusion should only apply to Attributes without a Namespace specified if (a.Namespace.Equals(String.Empty)) { if (RdfXmlSpecsHelper.IsAmbigiousAttributeName(a.LocalName)) { // Can't use any of the RDF terms that mandate the rdf: prefix without it throw new RdfParseException("An Attribute with an ambigious name '" + a.LocalName + "' was encountered. The following attribute names MUST have the rdf: prefix - about, aboutEach, ID, bagID, type, resource, parseType"); } } // URIRef encoding check if (!RdfXmlSpecsHelper.IsValidUriRefEncoding(a.Value)) { throw new RdfParseException("An Attribute with an incorrectly encoded URIRef was encountered, URIRef's must be encoded in Unicode Normal Form C"); } } return(el); }
/// <summary> /// Helper function which generates standardised Error Messages /// </summary> /// <param name="message">Error Message</param> /// <param name="production">The Production where the Error occurred</param> /// <param name="evt">Event causing the Error</param> /// <returns></returns> public static RdfParseException Error(String message, String production, IRdfXmlEvent evt) { StringBuilder output = new StringBuilder(); if (evt.Position != null) { output.Append('['); output.Append("Line "); output.Append(evt.Position.StartLine); output.Append(" Column "); output.Append(evt.Position.StartPosition); output.Append("] "); } output.AppendLine(message); if (!production.Equals(String.Empty)) { output.AppendLine("Occurred in Grammar Production '" + production + "'"); } if (!evt.SourceXml.Equals(String.Empty)) { output.AppendLine("[Source XML]"); output.AppendLine(evt.SourceXml); } if (evt.Position != null) { return(new RdfParseException(output.ToString(), evt.Position)); } else { return(new RdfParseException(output.ToString())); } }
/// <summary> /// Helper function which generates standardised Error Messages /// </summary> /// <param name="message">Error Message</param> /// <param name="production">The Production where the Error occurred</param> /// <param name="evt">Event causing the Error</param> /// <returns></returns> public static RdfParseException Error(String message, String production, IRdfXmlEvent evt) { StringBuilder output = new StringBuilder(); if (evt.Position != null) { output.Append('['); output.Append("Line "); output.Append(evt.Position.StartLine); output.Append(" Column "); output.Append(evt.Position.StartPosition); output.Append("] "); } output.AppendLine(message); if (!production.Equals(String.Empty)) output.AppendLine("Occurred in Grammar Production '" + production + "'"); if (!evt.SourceXml.Equals(String.Empty)) { output.AppendLine("[Source XML]"); output.AppendLine(evt.SourceXml); } if (evt.Position != null) { return new RdfParseException(output.ToString(), evt.Position); } else { return new RdfParseException(output.ToString()); } }
/// <summary> /// Helper function which generates standardised Error Messages /// </summary> /// <param name="message">Error Message</param> /// <param name="evt">Event causing the Error</param> /// <returns></returns> public static RdfParseException Error(String message, IRdfXmlEvent evt) { return(Error(message, String.Empty, evt)); }
/// <summary> /// Implementation of the RDF/XML Grammar Production 'parseTypeCollectionPropertyElt' /// </summary> /// <param name="context">Parser Context</param> /// <param name="eventlist">Queue of Events that make up the Collection Parse Type Property Element and its Children</param> /// <param name="parent">Parent Event (ie. Node) of the Property Element</param> private void GrammarProductionParseTypeCollectionPropertyElement(RdfXmlParserContext context, IEventQueue<IRdfXmlEvent> eventlist, IRdfXmlEvent parent) { //Tracing if (this._traceparsing) { this.ProductionTracePartial("Parse Type Collection Property Element"); } //Get the first Event, should be an ElementEvent //Type checking is done by the Parent Production IRdfXmlEvent first = eventlist.Dequeue(); ElementEvent element = (ElementEvent)first; if (this._traceparsing) this.ProductionTracePartial(element); //Apply Namespaces this.ApplyNamespaces(context, element); //Validate Attributes String ID = String.Empty; if (element.Attributes.Count > 2) { //Can't be more than 2 Attributes, only allowed an optional rdf:ID and a required rdf:parseType throw ParserHelper.Error("An Property Element with Parse Type 'Collection' was encountered with too many Attributes. Only rdf:ID and rdf:parseType are allowed on Property Elements with Parse Type 'Collection'", "Parse Type Collection Property Element", element); } else { //Check the attributes that do exist foreach (AttributeEvent a in element.Attributes) { if (RdfXmlSpecsHelper.IsIDAttribute(a)) { ID = "#" + a.Value; } else if (a.QName.Equals("rdf:parseType")) { //OK } else { //Invalid Attribute throw ParserHelper.Error("Unexpected Attribute '" + a.QName + "' was encountered on a Property Element with Parse Type 'Collection'. Only rdf:ID and rdf:parseType are allowed on Property Elements with Parse Type 'Collection'", "Parse Type Collection Property Element", element); } } } //Build sequence of Blank Nodes IRdfXmlEvent next; IRdfXmlEvent nodeElement; Queue<ElementEvent> seqNodes = new Queue<ElementEvent>(); while (eventlist.Count > 1) { #region Node Element Processing //Need to process the Node Element first //Create a new Sublist IEventQueue<IRdfXmlEvent> subevents = new EventQueue<IRdfXmlEvent>(); int nesting = 0; nodeElement = eventlist.Peek(); //Add Node Element to sequence seqNodes.Enqueue((ElementEvent)nodeElement); //Gather the Sublist taking account of nesting do { next = eventlist.Dequeue(); subevents.Enqueue(next); if (next is ElementEvent) { nesting++; } else if (next is EndElementEvent) { nesting--; } } while (nesting > 0); //Call the next Grammar Production this.GrammarProductionNodeElement(context, subevents); #endregion } //Build a triple expressing the start of the list (which may be an empty list) INode subj, pred, obj; INode firstPred, restPred; INode b1, b2; //Subject comes from Parent ElementEvent parentElement = (ElementEvent)parent; subj = parentElement.SubjectNode; //Validate the ID (if any) if (!ID.Equals(String.Empty)) { this.ValidateID(context, ID.Substring(1), subj); } //Predicate from the Element pred = this.Resolve(context, element);//context.Handler.CreateUriNode(element.QName); if (seqNodes.Count > 0) { //Non-empty list ElementEvent node; //Get first Element from the Queue node = seqNodes.Dequeue(); //Object is first thing in the Sequence which we create a Blank Node for b1 = context.Handler.CreateBlankNode(); //Assert if (!context.Handler.HandleTriple(new Triple(subj, pred, b1))) ParserHelper.Stop(); //Reify if applicable if (!ID.Equals(String.Empty)) { //Resolve the Uri UriReferenceEvent uriref = new UriReferenceEvent(ID, String.Empty); IUriNode uri = this.Resolve(context, uriref, element.BaseUri); this.Reify(context, uri, subj, pred, b1); } //Set the first element in the list subj = b1; firstPred = context.Handler.CreateUriNode(UriFactory.Create(RdfSpecsHelper.RdfListFirst)); if (!context.Handler.HandleTriple(new Triple(subj, firstPred, node.SubjectNode))) ParserHelper.Stop(); //Middle elements of the list restPred = context.Handler.CreateUriNode(UriFactory.Create(RdfSpecsHelper.RdfListRest)); while (seqNodes.Count >= 1) { node = seqNodes.Dequeue(); //Set Node 2 to be the rest of the previous items list b2 = context.Handler.CreateBlankNode(); if (!context.Handler.HandleTriple(new Triple(b1, restPred, b2))) ParserHelper.Stop(); //Set Node 2 to be the start of it's own list if (!context.Handler.HandleTriple(new Triple(b2, firstPred, node.SubjectNode))) ParserHelper.Stop(); b1 = b2; } //Set last element of the list to have its rest as nil if (!context.Handler.HandleTriple(new Triple(b1, restPred, context.Handler.CreateUriNode(UriFactory.Create(RdfSpecsHelper.RdfListNil))))) ParserHelper.Stop(); } else { //Empty list //Object is therefore rdf:nil obj = context.Handler.CreateUriNode(UriFactory.Create(RdfSpecsHelper.RdfListNil)); //Assert if (!context.Handler.HandleTriple(new Triple(subj, pred, obj))) ParserHelper.Stop(); //Reify if applicable if (!ID.Equals(String.Empty)) { //Resolve the Uri UriReferenceEvent uriref = new UriReferenceEvent(ID, String.Empty); IUriNode uri = this.Resolve(context, uriref, element.BaseUri); this.Reify(context, uri, subj, pred, obj); } } //Check last event is an EndElementEvent next = eventlist.Dequeue(); if (!(next is EndElementEvent)) { throw ParserHelper.Error("Unexpected Event '" + next.GetType().ToString() + "', expected an EndElementEvent to terminate a Parse Type Collection Property Element!", "Parse Type Collection Property Element", next); } }
/// <summary> /// Implementation of the RDF/XML Grammar Production 'literalPropertyElt' /// </summary> /// <param name="context">Parser Context</param> /// <param name="eventlist">Queue of Events that make up the Literal Property Element and its Children</param> /// <param name="parent">Parent Event (ie. Node) of the Property Element</param> private void GrammarProductionLiteralPropertyElement(RdfXmlParserContext context, IEventQueue<IRdfXmlEvent> eventlist, IRdfXmlEvent parent) { //Tracing if (this._traceparsing) { this.ProductionTracePartial("Literal Property Element"); } //Get the 3 Events (should only be three) IRdfXmlEvent first, middle, last; first = eventlist.Dequeue(); middle = eventlist.Dequeue(); last = eventlist.Dequeue(); //If Queue is non-empty then Error if (eventlist.Count > 0) { throw ParserHelper.Error("Too many events encountered while trying to parse a Literal Property Element", first); } ElementEvent element = (ElementEvent)first; if (this._traceparsing) this.ProductionTracePartial(element); //Apply Namespaces this.ApplyNamespaces(context, element); //Validate that the middle event is a TextEvent if (!(middle is TextEvent)) { throw ParserHelper.Error("Unexpected event '" + middle.GetType().ToString() + "', expected a TextEvent in a Literal Property Element", middle); } TextEvent text = (TextEvent)middle; //Validate the Attributes String ID = String.Empty; String datatype = String.Empty; if (element.Attributes.Count > 2) { throw ParserHelper.Error("A Literal Property Element contains too many attributes, only rdf:ID and rdf:datatype are permitted", element); } else { //Only rdf:ID and rdf:datatype allowed foreach (AttributeEvent a in element.Attributes) { if (RdfXmlSpecsHelper.IsIDAttribute(a)) { ID = "#" + a.Value; } else if (RdfXmlSpecsHelper.IsDataTypeAttribute(a)) { datatype = a.Value; } else { throw ParserHelper.Error("A Literal Property Element contains an unexpected attribute, only rdf:ID and rdf:datatype are permitted", element); } } } //Create the Nodes for the Graph INode subj, pred, obj; //Get the Subject from the Parent ElementEvent parentEl = (ElementEvent)parent; subj = parentEl.SubjectNode; //Validate the ID (if any) if (!ID.Equals(String.Empty)) { this.ValidateID(context, ID.Substring(1), subj); } //Create a Predicate from this Element pred = this.Resolve(context, element);//context.Handler.CreateUriNode(element.QName); //Create an Object from the Text Event if (datatype.Equals(String.Empty)) { //No Type with possible Language if (element.Language.Equals(String.Empty)) { obj = context.Handler.CreateLiteralNode(text.Value); } else { obj = context.Handler.CreateLiteralNode(text.Value, element.Language); } } else { //Typed //Resolve the Datatype Uri UriReferenceEvent dtref = new UriReferenceEvent(datatype, String.Empty); IUriNode dturi = this.Resolve(context, dtref, element.BaseUri); obj = context.Handler.CreateLiteralNode(text.Value, dturi.Uri); } //Assert the Triple if (!context.Handler.HandleTriple(new Triple(subj, pred, obj))) ParserHelper.Stop(); //Reify if applicable if (!ID.Equals(String.Empty)) { //Resolve the Uri UriReferenceEvent uriref = new UriReferenceEvent(ID, String.Empty); IUriNode uri = this.Resolve(context, uriref,element.BaseUri); this.Reify(context, uri, subj, pred, obj); } }
/// <summary> /// Adds an event to the Queue /// </summary> /// <param name="e">Event</param> public override void Enqueue(IRdfXmlEvent e) { if (e != null) { if (e is ClearQueueEvent) { this.Clear(); } else { base.Enqueue(e); } } }
/// <summary> /// Gets the next event from the XML stream /// </summary> /// <returns></returns> public IRdfXmlEvent GetNextEvent() { if (this._stop) return null; //If the Root Element is filled then return it if (this._rootEl != null) { IRdfXmlEvent temp = this._rootEl; this._rootEl = null; return temp; } //If Literal Parsing flag is set then we've just read an element which had rdf:parseType="Literal" if (this._parseLiteral) { this._requireEndElement = true; this._parseLiteral = false; this._noRead = true; this._reader.MoveToContent(); String data = this._reader.ReadInnerXml(); return new TypedLiteralEvent(data, RdfSpecsHelper.RdfXmlLiteral, data, this.GetPosition()); } //If we need to return an end element then do so if (this._requireEndElement) { this._requireEndElement = false; this._currentBaseUri = this._baseUris.Pop(); return new EndElementEvent(this.GetPosition()); } //If at EOF throw an error if (this._reader.EOF) throw new RdfParseException("Unable to read further events as the end of the stream has already been reached"); //Otherwise attempt to read the next node bool read = true; if (!this._noRead) { read = this._reader.Read(); } else { this._noRead = false; } if (read) { //Return the appropriate event for the Node Type switch (this._reader.NodeType) { case XmlNodeType.Element: //Element if (this._first) { this._first = false; this._rdfRootSeen = this.IsName("RDF", NamespaceMapper.RDF); this._rootEl = this.GetElement(); RootEvent root = new RootEvent(this.GetBaseUri(), this._reader.Value, this.GetPosition()); root.DocumentElement = (ElementEvent)this._rootEl; root.Children.Add((ElementEvent)this._rootEl); return root; } else { if (!this._first && this.IsName("RDF", NamespaceMapper.RDF)) { if (this._rdfRootSeen) throw new RdfParseException("Unexpected nested rdf:RDF node encountered, this is not valid RDF/XML syntax"); this._noRead = true; this._first = true; return new ClearQueueEvent(); } return this.GetElement(); } case XmlNodeType.EndElement: //End of an Element this._currentBaseUri = this._baseUris.Pop(); if (this.IsName("RDF", NamespaceMapper.RDF)) { this._stop = true; } return new EndElementEvent(this.GetPosition()); case XmlNodeType.Attribute: //Attribute throw new RdfParseException("Unexpected Attribute Node encountered"); case XmlNodeType.Text: return new TextEvent(this._reader.Value, this._reader.Value, this.GetPosition()); case XmlNodeType.CDATA: return new TextEvent(this._reader.Value, this._reader.Value, this.GetPosition()); case XmlNodeType.Document: case XmlNodeType.DocumentType: case XmlNodeType.XmlDeclaration: case XmlNodeType.Comment: case XmlNodeType.ProcessingInstruction: case XmlNodeType.Notation: case XmlNodeType.Whitespace: //Node Types that don't generate events and just indicate to continue reading return this.GetNextEvent(); default: throw new RdfParseException("Unexpected XML Node Type " + this._reader.NodeType.ToString() + " encountered"); } } else { return null; } }
/// <summary> /// Takes the Event Tree and Flattens it into a Queue as per the rules laid out in the RDF/XML Specification /// </summary> /// <param name="context">Parser Context</param> /// <param name="evt">Event which is the Root of the Tree (not necessarily a RootEvent)</param> /// <param name="nesting">A numeric value used for Parser Tracing to indicate nesting levels of the Event Tree</param> private void FlattenEventTree(RdfXmlParserContext context, IRdfXmlEvent evt, int nesting) { //Add to Queue context.Events.Enqueue(evt); if (context.TraceParsing) { Console.Write(nesting + " " + evt.GetType().ToString()); } //Iterate over Children where present if (evt is RootEvent) { RootEvent root = (RootEvent)evt; if (context.TraceParsing) { Console.WriteLine(""); } foreach (IRdfXmlEvent childEvent in root.Children) { this.FlattenEventTree(context, childEvent, nesting + 1); } //No End after a RootEvent return; } else if (evt is ElementEvent) { ElementEvent element = (ElementEvent)evt; if (context.TraceParsing) { Console.WriteLine(" " + element.Namespace + ":" + element.LocalName); } if (element.Children.Count > 0) { foreach (IRdfXmlEvent childEvent in element.Children) { this.FlattenEventTree(context, childEvent, nesting + 1); } } } else if (evt is TextEvent) { TextEvent text = (TextEvent)evt; if (context.TraceParsing) { Console.WriteLine(" " + text.Value); } //No additional End after a Text Event return; } else if (evt is TypedLiteralEvent) { TypedLiteralEvent tlit = (TypedLiteralEvent)evt; if (context.TraceParsing) { Console.WriteLine(); } //No additional End after a Text Event return; } //Add an End Element Event to the Queue EndElementEvent end = new EndElementEvent(); context.Events.Enqueue(end); if (context.TraceParsing) { String endDescrip = String.Empty; if (evt is ElementEvent) { ElementEvent temp = (ElementEvent)evt; endDescrip = " " + temp.QName; } Console.WriteLine(nesting + " " + end.GetType().ToString() + endDescrip); } }
/// <summary> /// Implementation of the RDF/XML Grammar Production 'propertyEltList' /// </summary> /// <param name="context">Parser Context</param> /// <param name="eventlist">Queue of Events to apply the Production to</param> /// <param name="parent">Parent Event (ie. Node) of the Property Elements</param> private void GrammarProductionPropertyElementList(RdfXmlParserContext context, IEventQueue<IRdfXmlEvent> eventlist, IRdfXmlEvent parent) { //Tracing if (this._traceparsing) { this.ProductionTrace("Property Element List"); } IRdfXmlEvent next; //Want to break up into a number of sublists while (eventlist.Count > 0) { //Create a new Sublist IEventQueue<IRdfXmlEvent> subevents = new EventQueue<IRdfXmlEvent>(); int nesting = 0; //Gather the Sublist taking account of nesting do { next = eventlist.Dequeue(); subevents.Enqueue(next); if (next is ElementEvent) { nesting++; } else if (next is EndElementEvent) { nesting--; } } while (nesting > 0); //Call the next Grammar Production if (subevents.Count > 0) this.GrammarProductionPropertyElement(context, subevents, parent); } }
/// <summary> /// Implementation of the RDF/XML Grammar Production 'propertyElt' /// </summary> /// <param name="context">Parser Context</param> /// <param name="eventlist">Queue of Events that make up the Property Element and its Children</param> /// <param name="parent">Parent Event (ie. Node) of the Property Element</param> private void GrammarProductionPropertyElement(RdfXmlParserContext context, IEventQueue<IRdfXmlEvent> eventlist, IRdfXmlEvent parent) { //Tracing if (this._traceparsing) { this.ProductionTracePartial("Property Element"); } //Get first thing from the Queue IRdfXmlEvent first = eventlist.Dequeue(); ElementEvent element; //Must be an ElementEvent if (!(first is ElementEvent)) { //Unexpected Event throw ParserHelper.Error("Expected an ElementEvent but encountered a '" + first.GetType().ToString() + "'", "PropertyElement", first); } //Validate the Uri element = (ElementEvent)first; if (this._traceparsing) this.ProductionTracePartial(element); this.ApplyNamespaces(context, element); if (!RdfXmlSpecsHelper.IsPropertyElementURI(element.QName)) { //Invalid Uri throw ParserHelper.Error("A Property Element was encountered with an invalid URI '" + element.QName + "'\nCore Syntax Terms, Old Syntax Terms and rdf:Description cannot be used as Property Element URIs", "PropertyElement", element); } //List Expansion if (element.QName.Equals("rdf:li")) { UriReferenceEvent u = this.ListExpand(parent); element.SetUri(u); } //Need to select what to do based on the Type of Property Element IRdfXmlEvent next = eventlist.Peek(); //This call inserts the first element back at the head of the queue //Most of the sub-productions here need this //Would ideally use Stacks instead of Queues but Queues make more sense for most of the Parsing this.QueueJump(eventlist, first); if (element.ParseType == RdfXmlParseType.None) { //A Resource/Literal Property Element if (next is ElementEvent) { //Resource this.GrammarProductionResourcePropertyElement(context, eventlist, parent); } else if (next is TextEvent) { //Literal this.GrammarProductionLiteralPropertyElement(context, eventlist, parent); } else if (next is EndElementEvent) { //An Empty Property Element this.GrammarProductionEmptyPropertyElement(context, element, parent); } else { //Error throw ParserHelper.Error("An Element which should be Parsed with the Default Parsing Rules was encountered without a valid subsequent Event - Parser cannot proceed!", "Property Element", element); } } else if (element.ParseType == RdfXmlParseType.Literal) { //A rdf:parseType="Literal" Property Element this.GrammarProductionParseTypeLiteralPropertyElement(context, eventlist, parent); } else if (element.ParseType == RdfXmlParseType.Collection) { //A rdf:parseType="Collection" Property Element this.GrammarProductionParseTypeCollectionPropertyElement(context, eventlist, parent); } else if (element.ParseType == RdfXmlParseType.Resource) { //A rdf:parseType="Resource" Property Element this.GrammarProductionParseTypeResourcePropertyElement(context, eventlist, parent); } else if (next is EndElementEvent) { //An Empty Property Element this.GrammarProductionEmptyPropertyElement(context, element, parent); } else { //Error throw ParserHelper.Error("An Element without a known Parse Type was encountered Or the Parser was unable to determine what to do based on the subsequent event - Parser cannot proceed!", "Node Element", element); } }
/// <summary> /// Implementation of the RDF/XML Grammar Production 'parseTypeResourcePropertyElt' /// </summary> /// <param name="context">Parser Context</param> /// <param name="eventlist">Queue of Events that make up the Resource Parse Type Property Element and its Children</param> /// <param name="parent">Parent Event (ie. Node) of the Property Element</param> private void GrammarProductionParseTypeResourcePropertyElement(RdfXmlParserContext context, IEventQueue<IRdfXmlEvent> eventlist, IRdfXmlEvent parent) { //Tracing if (this._traceparsing) { this.ProductionTracePartial("Parse Type Resource Property Element"); } //Get the first Event, should be an ElementEvent //Type checking is done by the Parent Production IRdfXmlEvent first = eventlist.Dequeue(); ElementEvent element = (ElementEvent)first; if (this._traceparsing) this.ProductionTracePartial(element); //Apply Namespaces this.ApplyNamespaces(context, element); //Validate Attributes String ID = String.Empty; if (element.Attributes.Count > 2) { //Can't be more than 2 Attributes, only allowed an optional rdf:ID and a required rdf:parseType throw ParserHelper.Error("An Property Element with Parse Type 'Resource' was encountered with too many Attributes. Only rdf:ID and rdf:parseType are allowed on Property Elements with Parse Type 'Resource'", "Parse Type Resource Property Element", element); } else { //Check the attributes that do exist foreach (AttributeEvent a in element.Attributes) { if (RdfXmlSpecsHelper.IsIDAttribute(a)) { ID = "#" + a.Value; } else if (a.QName.Equals("rdf:parseType")) { //OK } else { //Invalid Attribute throw ParserHelper.Error("Unexpected Attribute '" + a.QName + "' was encountered on a Property Element with Parse Type 'Resource'. Only rdf:ID and rdf:parseType are allowed on Property Elements with Parse Type 'Resource'", "Parse Type Resource Property Element", element); } } } //Add a Triple about this INode subj, pred, obj; //Get the Subject from the Parent ElementEvent parentEvent = (ElementEvent)parent; subj = parentEvent.SubjectNode; //Validate the ID (if any) if (!ID.Equals(String.Empty)) { this.ValidateID(context, ID.Substring(1), subj); } //Create the Predicate from the Element pred = this.Resolve(context, element);//context.Handler.CreateUriNode(element.QName); //Generate a Blank Node ID for the Object obj = context.Handler.CreateBlankNode(); //Assert if (!context.Handler.HandleTriple(new Triple(subj, pred, obj))) ParserHelper.Stop(); //Reify if applicable if (!ID.Equals(String.Empty)) { //Resolve the Uri UriReferenceEvent uriref = new UriReferenceEvent(ID, String.Empty); IUriNode uri = this.Resolve(context, uriref,element.BaseUri); this.Reify(context, uri, subj, pred, obj); } //Get the next event in the Queue which should be either an Element Event or a End Element Event //Validate this IRdfXmlEvent next = eventlist.Dequeue(); if (next is EndElementEvent) { //Content is Empty so nothing else to do } else if (next is ElementEvent) { //Non-Empty Content so need to build a sequence of new events IEventQueue<IRdfXmlEvent> subEvents = new EventQueue<IRdfXmlEvent>(); //Create an rdf:Description event as the container ElementEvent descrip = new ElementEvent("rdf:Description", element.BaseUri, String.Empty); descrip.Subject = new BlankNodeIDEvent(String.Empty); descrip.SubjectNode = obj; subEvents.Enqueue(descrip); //Add the current element we were looking at subEvents.Enqueue(next); //Add rest of events in list (exceot the last) while (eventlist.Count > 1) { subEvents.Enqueue(eventlist.Dequeue()); } //Terminate with an EndElement Event subEvents.Enqueue(new EndElementEvent()); //Process with Node Element Production this.GrammarProductionNodeElement(context, subEvents); //Get the last thing in the List next = eventlist.Dequeue(); } else { throw ParserHelper.Error("Unexpected Event '" + next.GetType().ToString() + "', expected an ElementEvent or EndElementEvent after a Parse Type Resource Property Element!", "Parse Type Resource Property Element", next); } //Check for the last thing being an EndElement Event if (!(next is EndElementEvent)) { throw ParserHelper.Error("Unexpected Event '" + next.GetType().ToString() + "', expected an EndElementEvent to terminate a Parse Type Resource Property Element!", "Parse Type Resource Property Element", next); } }
/// <summary> /// Implementation of the RDF/XML Grammar Production 'parseTypeLiteralPropertyElt' /// </summary> /// <param name="context">Parser Context</param> /// <param name="eventlist">Queue of Events that make up the Literal Parse Type Property Element and its Children</param> /// <param name="parent">Parent Event (ie. Node) of the Property Element</param> private void GrammarProductionParseTypeLiteralPropertyElement(RdfXmlParserContext context, IEventQueue<IRdfXmlEvent> eventlist, IRdfXmlEvent parent) { //Tracing if (this._traceparsing) { this.ProductionTracePartial("Parse Type Literal Property Element"); } //Get the first Event, should be an ElementEvent //Type checking is done by the Parent Production IRdfXmlEvent first = eventlist.Dequeue(); ElementEvent element = (ElementEvent)first; if (this._traceparsing) this.ProductionTracePartial(element); //Apply Namespaces this.ApplyNamespaces(context, element); //Validate Attributes String ID = String.Empty; if (element.Attributes.Count > 2) { //Can't be more than 2 Attributes, only allowed an optional rdf:ID and a required rdf:parseType throw ParserHelper.Error("An Property Element with Parse Type 'Literal' was encountered with too many Attributes. Only rdf:ID and rdf:parseType are allowed on Property Elements with Parse Type 'Literal'", "Parse Type Literal Property Element", element); } else { //Check the attributes that do exist foreach (AttributeEvent a in element.Attributes) { if (RdfXmlSpecsHelper.IsIDAttribute(a)) { ID = "#" + a.Value; } else if (a.QName.Equals("rdf:parseType")) { //OK } else { //Invalid Attribute throw ParserHelper.Error("Unexpected Attribute '" + a.QName + "' was encountered on a Property Element with Parse Type 'Literal'. Only rdf:ID and rdf:parseType are allowed on Property Elements with Parse Type 'Literal'", "Parse Type Literal Property Element", element); } } } //Get the next event in the Queue which should be a TypedLiteralEvent //Validate this IRdfXmlEvent lit = eventlist.Dequeue(); if (!(lit is TypedLiteralEvent)) { throw ParserHelper.Error("Unexpected Event '" + lit.GetType().ToString() + "', expected a TypedLiteralEvent after a Property Element with Parse Type 'Literal'", "Parse Type Literal Property Element", lit); } //Get the Subject from the Parent INode subj, pred, obj; ElementEvent parentEl = (ElementEvent) parent; subj = parentEl.SubjectNode; //Validate the ID (if any) if (!ID.Equals(String.Empty)) { this.ValidateID(context, ID.Substring(1), subj); } //Create the Predicate from the Element pred = this.Resolve(context, element);//context.Handler.CreateUriNode(element.QName); //Create the Object from the Typed Literal TypedLiteralEvent tlit = (TypedLiteralEvent)lit; //At the moment we're just going to ensure that we normalize it to Unicode Normal Form C String xmllit = tlit.Value; #if !NO_NORM xmllit = xmllit.Normalize(); #endif obj = context.Handler.CreateLiteralNode(xmllit, UriFactory.Create(tlit.DataType)); //Assert the Triple if (!context.Handler.HandleTriple(new Triple(subj, pred, obj))) ParserHelper.Stop(); //Reify if applicable if (!ID.Equals(String.Empty)) { //Resolve the Uri UriReferenceEvent uriref = new UriReferenceEvent(ID, String.Empty); IUriNode uri = this.Resolve(context, uriref,element.BaseUri); this.Reify(context, uri, subj, pred, obj); } //Check for the last thing being an EndElement Event IRdfXmlEvent next = eventlist.Dequeue(); if (!(next is EndElementEvent)) { throw ParserHelper.Error("Unexpected Event '" + next.GetType().ToString() + "', expected an EndElementEvent to terminate a Parse Type Literal Property Element!", "Parse Type Literal Property Element", next); } }
/// <summary> /// Takes the Event Tree and Flattens it into a Queue as per the rules laid out in the RDF/XML Specification /// </summary> /// <param name="context">Parser Context</param> /// <param name="evt">Event which is the Root of the Tree (not necessarily a RootEvent)</param> /// <param name="nesting">A numeric value used for Parser Tracing to indicate nesting levels of the Event Tree</param> private void FlattenEventTree(RdfXmlParserContext context, IRdfXmlEvent evt, int nesting) { // Add to Queue context.Events.Enqueue(evt); if (context.TraceParsing) { Console.Write(nesting + " " + evt.GetType().ToString()); } // Iterate over Children where present if (evt is RootEvent) { RootEvent root = (RootEvent)evt; if (context.TraceParsing) { Console.WriteLine(""); } foreach (IRdfXmlEvent childEvent in root.Children) { FlattenEventTree(context, childEvent, nesting + 1); } // No End after a RootEvent return; } else if (evt is ElementEvent) { ElementEvent element = (ElementEvent)evt; if (context.TraceParsing) { Console.WriteLine(" " + element.Namespace + ":" + element.LocalName); } if (element.Children.Count > 0) { foreach (IRdfXmlEvent childEvent in element.Children) { FlattenEventTree(context, childEvent, nesting + 1); } } } else if (evt is TextEvent) { TextEvent text = (TextEvent)evt; if (context.TraceParsing) { Console.WriteLine(" " + text.Value); } // No additional End after a Text Event return; } else if (evt is TypedLiteralEvent) { TypedLiteralEvent tlit = (TypedLiteralEvent)evt; if (context.TraceParsing) { Console.WriteLine(); } // No additional End after a Text Event return; } // Add an End Element Event to the Queue EndElementEvent end = new EndElementEvent(); context.Events.Enqueue(end); if (context.TraceParsing) { String endDescrip = String.Empty; if (evt is ElementEvent) { ElementEvent temp = (ElementEvent)evt; endDescrip = " " + temp.QName; } Console.WriteLine(nesting + " " + end.GetType().ToString() + endDescrip); } }
/// <summary> /// Given an XML Node creates the relevant RDF/XML Events for it and recurses as necessary /// </summary> /// <param name="context">Parser Context</param> /// <param name="node">The Node to create Event(s) from</param> /// <param name="parent">The Parent Node of the given Node</param> /// <returns></returns> private ElementEvent GenerateEvents(RdfXmlParserContext context, XmlNode node, IRdfXmlEvent parent) { // Get the Base Uri String baseUri = String.Empty; if (parent is ElementEvent) { baseUri = ((ElementEvent)parent).BaseUri; } // Create an ElementEvent for the Node ElementEvent element = new ElementEvent(node.LocalName, node.Prefix, baseUri, node.OuterXml); // Set the initial Language from the Parent ElementEvent parentEl = (ElementEvent)parent; element.Language = parentEl.Language; #region Attribute Processing // Iterate over Attributes bool parseTypeLiteral = false; foreach (XmlAttribute attr in node.Attributes) { // Watch out for special attributes if (attr.Name == "xml:lang") { // Set Language element.Language = attr.Value; } else if (attr.Name == "xml:base") { // Set Base Uri if (RdfXmlSpecsHelper.IsAbsoluteURI(attr.Value)) { // Absolute Uri element.BaseUri = attr.Value; } else if (!element.BaseUri.Equals(String.Empty)) { // Relative Uri with a Base Uri to resolve against // element.BaseUri += attr.Value; element.BaseUri = Tools.ResolveUri(attr.Value, element.BaseUri); } else { // Relative Uri with no Base Uri throw new RdfParseException("Cannot resolve a Relative Base URI since there is no in-scope Base URI"); } } else if (attr.Prefix == "xmlns") { // Register a Namespace String uri; if (attr.Value.StartsWith("http://")) { // Absolute Uri uri = attr.Value; } else if (!element.BaseUri.Equals(String.Empty)) { // Relative Uri with a Base Uri to resolve against // uri = element.BaseUri + attr.Value; uri = Tools.ResolveUri(attr.Value, element.BaseUri); } else { // Relative Uri with no Base Uri throw new RdfParseException("Cannot resolve a Relative Namespace URI since there is no in-scope Base URI"); } NamespaceAttributeEvent ns = new NamespaceAttributeEvent(attr.LocalName, uri, attr.OuterXml); element.NamespaceAttributes.Add(ns); } else if (attr.Prefix == String.Empty && attr.Name == "xmlns") { // Register a Default Namespace (Empty Prefix) String uri; if (attr.Value.StartsWith("http://")) { // Absolute Uri uri = attr.Value; } else if (!element.BaseUri.Equals(String.Empty)) { // Relative Uri with a Base Uri to resolve against // uri = element.BaseUri + attr.Value; uri = Tools.ResolveUri(attr.Value, element.BaseUri); } else { // Relative Uri with no Base Uri throw new RdfParseException("Cannot resolve a Relative Namespace URI since there is no in-scope Base URI"); } NamespaceAttributeEvent ns = new NamespaceAttributeEvent(String.Empty, uri, attr.OuterXml); element.NamespaceAttributes.Add(ns); } else if (attr.Prefix == "xml" || (attr.Prefix == String.Empty && attr.LocalName.StartsWith("xml"))) { // Ignore other Reserved XML Names } else if (attr.Name == "rdf:parseType" && attr.Value == "Literal") { // Literal Parse Type parseTypeLiteral = true; // Create the Attribute AttributeEvent attrEvent = new AttributeEvent(attr.LocalName, attr.Prefix, attr.Value, attr.OuterXml); element.Attributes.Add(attrEvent); // Set ParseType property correctly element.ParseType = RdfXmlParseType.Literal; } else if (attr.Name == "rdf:parseType") { // Some other Parse Type // Create the Attribute AttributeEvent attrEvent = new AttributeEvent(attr.LocalName, attr.Prefix, attr.Value, attr.OuterXml); element.Attributes.Add(attrEvent); // Set the ParseType property correctly if (attr.Value == "Resource") { element.ParseType = RdfXmlParseType.Resource; } else if (attr.Value == "Collection") { element.ParseType = RdfXmlParseType.Collection; } else { // Have to assume Literal element.ParseType = RdfXmlParseType.Literal; parseTypeLiteral = true; // Replace the Parse Type attribute with one saying it is Literal element.Attributes.Remove(attrEvent); attrEvent = new AttributeEvent(attr.LocalName, attr.Prefix, "Literal", attr.OuterXml); } } else { // Normal Attribute which we generate an Event from AttributeEvent attrEvent = new AttributeEvent(attr.LocalName, attr.Prefix, attr.Value, attr.OuterXml); element.Attributes.Add(attrEvent); } } // Validate generated Attributes for Namespace Confusion and URIRef encoding foreach (AttributeEvent a in element.Attributes) { // Namespace Confusion should only apply to Attributes without a Namespace specified if (a.Namespace.Equals(String.Empty)) { if (RdfXmlSpecsHelper.IsAmbigiousAttributeName(a.LocalName)) { // Can't use any of the RDF terms that mandate the rdf: prefix without it throw ParserHelper.Error("An Attribute with an ambigious name '" + a.LocalName + "' was encountered. The following attribute names MUST have the rdf: prefix - about, aboutEach, ID, bagID, type, resource, parseType", element); } } // URIRef encoding check if (!RdfXmlSpecsHelper.IsValidUriRefEncoding(a.Value)) { throw ParserHelper.Error("An Attribute with an incorrectly encoded URIRef was encountered, URIRef's must be encoded in Unicode Normal Form C", a); } } #endregion // Don't proceed if Literal Parse Type is on if (parseTypeLiteral) { // Generate an XMLLiteral from its Inner Xml (if any) TypedLiteralEvent lit = new TypedLiteralEvent(node.InnerXml.Normalize(), RdfSpecsHelper.RdfXmlLiteral, node.InnerXml); element.Children.Add(lit); return(element); } // Are there Child Nodes? if (node.HasChildNodes) { // Take different actions depending on the Number and Type of Child Nodes if (node.ChildNodes.Count > 1) { // Multiple Child Nodes // Iterate over Child Nodes foreach (XmlNode child in node.ChildNodes) { // Ignore Irrelevant Node Types if (IsIgnorableNode(child)) { continue; } // Generate an Event for the Child Node ElementEvent childEvent = GenerateEvents(context, child, element); element.Children.Add(childEvent); } } else if (node.ChildNodes[0].NodeType == XmlNodeType.Text) { // Single Child which is a Text Node // Generate a Text Event TextEvent text = new TextEvent(node.InnerText.Normalize(), node.OuterXml); element.Children.Add(text); } else if (node.ChildNodes[0].NodeType == XmlNodeType.CDATA) { // Single Child which is a CData Node TextEvent text = new TextEvent(node.InnerXml.Normalize(), node.OuterXml); element.Children.Add(text); } else { // Single Child which is not a Text Node // Recurse on the single Child Node if (!IsIgnorableNode(node.ChildNodes[0])) { ElementEvent childEvent = GenerateEvents(context, node.ChildNodes[0], element); element.Children.Add(childEvent); } } } return(element); }
/// <summary> /// Adds an event to the end of the Queue /// </summary> /// <param name="e">Event</param> public override void Enqueue(IRdfXmlEvent e) { this._events.Enqueue(e); }
/// <summary> /// Given an XML Node creates the relevant RDF/XML Events for it and recurses as necessary /// </summary> /// <param name="context">Parser Context</param> /// <param name="node">The Node to create Event(s) from</param> /// <param name="parent">The Parent Node of the given Node</param> /// <returns></returns> private ElementEvent GenerateEvents(RdfXmlParserContext context, XmlNode node, IRdfXmlEvent parent) { //Get the Base Uri String baseUri = String.Empty; if (parent is ElementEvent) { baseUri = ((ElementEvent)parent).BaseUri; } //Create an ElementEvent for the Node ElementEvent element = new ElementEvent(node.LocalName, node.Prefix, baseUri, node.OuterXml); //Set the initial Language from the Parent ElementEvent parentEl = (ElementEvent)parent; element.Language = parentEl.Language; #region Attribute Processing //Iterate over Attributes bool parseTypeLiteral = false; foreach (XmlAttribute attr in node.Attributes) { //Watch out for special attributes if (attr.Name == "xml:lang") { //Set Language element.Language = attr.Value; } else if (attr.Name == "xml:base") { //Set Base Uri if (RdfXmlSpecsHelper.IsAbsoluteURI(attr.Value)) { //Absolute Uri element.BaseUri = attr.Value; } else if (!element.BaseUri.Equals(String.Empty)) { //Relative Uri with a Base Uri to resolve against //element.BaseUri += attr.Value; element.BaseUri = Tools.ResolveUri(attr.Value, element.BaseUri); } else { //Relative Uri with no Base Uri throw new RdfParseException("Cannot resolve a Relative Base URI since there is no in-scope Base URI"); } } else if (attr.Prefix == "xmlns") { //Register a Namespace String uri; if (attr.Value.StartsWith("http://")) { //Absolute Uri uri = attr.Value; } else if (!element.BaseUri.Equals(String.Empty)) { //Relative Uri with a Base Uri to resolve against //uri = element.BaseUri + attr.Value; uri = Tools.ResolveUri(attr.Value, element.BaseUri); } else { //Relative Uri with no Base Uri throw new RdfParseException("Cannot resolve a Relative Namespace URI since there is no in-scope Base URI"); } NamespaceAttributeEvent ns = new NamespaceAttributeEvent(attr.LocalName, uri, attr.OuterXml); element.NamespaceAttributes.Add(ns); } else if (attr.Prefix == String.Empty && attr.Name == "xmlns") { //Register a Default Namespace (Empty Prefix) String uri; if (attr.Value.StartsWith("http://")) { //Absolute Uri uri = attr.Value; } else if (!element.BaseUri.Equals(String.Empty)) { //Relative Uri with a Base Uri to resolve against //uri = element.BaseUri + attr.Value; uri = Tools.ResolveUri(attr.Value, element.BaseUri); } else { //Relative Uri with no Base Uri throw new RdfParseException("Cannot resolve a Relative Namespace URI since there is no in-scope Base URI"); } NamespaceAttributeEvent ns = new NamespaceAttributeEvent(String.Empty, uri, attr.OuterXml); element.NamespaceAttributes.Add(ns); } else if (attr.Prefix == "xml" || (attr.Prefix == String.Empty && attr.LocalName.StartsWith("xml"))) { //Ignore other Reserved XML Names } else if (attr.Name == "rdf:parseType" && attr.Value == "Literal") { //Literal Parse Type parseTypeLiteral = true; //Create the Attribute AttributeEvent attrEvent = new AttributeEvent(attr.LocalName, attr.Prefix, attr.Value, attr.OuterXml); element.Attributes.Add(attrEvent); //Set ParseType property correctly element.ParseType = RdfXmlParseType.Literal; } else if (attr.Name == "rdf:parseType") { //Some other Parse Type //Create the Attribute AttributeEvent attrEvent = new AttributeEvent(attr.LocalName, attr.Prefix, attr.Value, attr.OuterXml); element.Attributes.Add(attrEvent); //Set the ParseType property correctly if (attr.Value == "Resource") { element.ParseType = RdfXmlParseType.Resource; } else if (attr.Value == "Collection") { element.ParseType = RdfXmlParseType.Collection; } else { //Have to assume Literal element.ParseType = RdfXmlParseType.Literal; parseTypeLiteral = true; //Replace the Parse Type attribute with one saying it is Literal element.Attributes.Remove(attrEvent); attrEvent = new AttributeEvent(attr.LocalName, attr.Prefix, "Literal", attr.OuterXml); } } else { //Normal Attribute which we generate an Event from AttributeEvent attrEvent = new AttributeEvent(attr.LocalName, attr.Prefix, attr.Value, attr.OuterXml); element.Attributes.Add(attrEvent); } } //Validate generated Attributes for Namespace Confusion and URIRef encoding foreach (AttributeEvent a in element.Attributes) { //Namespace Confusion should only apply to Attributes without a Namespace specified if (a.Namespace.Equals(String.Empty)) { if (RdfXmlSpecsHelper.IsAmbigiousAttributeName(a.LocalName)) { //Can't use any of the RDF terms that mandate the rdf: prefix without it throw ParserHelper.Error("An Attribute with an ambigious name '" + a.LocalName + "' was encountered. The following attribute names MUST have the rdf: prefix - about, aboutEach, ID, bagID, type, resource, parseType", element); } } //URIRef encoding check if (!RdfXmlSpecsHelper.IsValidUriRefEncoding(a.Value)) { throw ParserHelper.Error("An Attribute with an incorrectly encoded URIRef was encountered, URIRef's must be encoded in Unicode Normal Form C", a); } } #endregion //Don't proceed if Literal Parse Type is on if (parseTypeLiteral) { //Generate an XMLLiteral from its Inner Xml (if any) TypedLiteralEvent lit = new TypedLiteralEvent(node.InnerXml.Normalize(), RdfSpecsHelper.RdfXmlLiteral, node.InnerXml); element.Children.Add(lit); return element; } //Are there Child Nodes? if (node.HasChildNodes) { //Take different actions depending on the Number and Type of Child Nodes if (node.ChildNodes.Count > 1) { //Multiple Child Nodes //Iterate over Child Nodes foreach (XmlNode child in node.ChildNodes) { //Ignore Irrelevant Node Types if (this.IsIgnorableNode(child)) { continue; } //Generate an Event for the Child Node ElementEvent childEvent = this.GenerateEvents(context, child, element); element.Children.Add(childEvent); } } else if (node.ChildNodes[0].NodeType == XmlNodeType.Text) { //Single Child which is a Text Node //Generate a Text Event TextEvent text = new TextEvent(node.InnerText.Normalize(), node.OuterXml); element.Children.Add(text); } else if (node.ChildNodes[0].NodeType == XmlNodeType.CDATA) { //Single Child which is a CData Node TextEvent text = new TextEvent(node.InnerXml.Normalize(), node.OuterXml); element.Children.Add(text); } else { //Single Child which is not a Text Node //Recurse on the single Child Node if (!this.IsIgnorableNode(node.ChildNodes[0])) { ElementEvent childEvent = this.GenerateEvents(context, node.ChildNodes[0], element); element.Children.Add(childEvent); } } } return element; }
/// <summary> /// Implementation of the RDF/XML Grammar Production 'resourcePropertyElt' /// </summary> /// <param name="context">Parser Context</param> /// <param name="eventlist">Queue of Events that make up the Resource Property Element and its Children</param> /// <param name="parent">Parent Event (ie. Node) of the Property Element</param> private void GrammarProductionResourcePropertyElement(RdfXmlParserContext context, IEventQueue<IRdfXmlEvent> eventlist, IRdfXmlEvent parent) { //Tracing if (this._traceparsing) { this.ProductionTracePartial("Resource Property Element"); } //Cast to an ElementEvent //We don't validate type here since we know this will be an ElementEvent because the calling function //will have done this validation previously IRdfXmlEvent first = eventlist.Dequeue(); IRdfXmlEvent next = eventlist.Peek(); ElementEvent element = (ElementEvent)first; if (this._traceparsing) this.ProductionTracePartial(element); //Apply Namespaces this.ApplyNamespaces(context, element); //Only allowed one attribute max which must be an ID attribute String ID = String.Empty; if (element.Attributes.Count > 1) { throw ParserHelper.Error("A Resource Property Element contains too many Attributes, only rdf:ID is permitted", element); } else if (element.Attributes.Count == 1) { if (!RdfXmlSpecsHelper.IsIDAttribute(element.Attributes.First())) { throw ParserHelper.Error("A Resource Property Element was encountered with a single attribute which was not rdf:ID, only rdf:ID is permitted", element); } else { ID = element.Attributes.First().Value; } } //Next must be an ElementEvent if (!(next is ElementEvent)) { throw ParserHelper.Error("Unexpected Event '" + next.GetType().ToString() + "', expected an ElementEvent as the first Event in a Resource Property Elements Event list", next); } //Get list of Sub Events IEventQueue<IRdfXmlEvent> subevents = new EventQueue<IRdfXmlEvent>(); while (eventlist.Count > 1) { subevents.Enqueue(eventlist.Dequeue()); } this.GrammarProductionNodeElement(context, subevents); //Check Last is an EndElementEvent IRdfXmlEvent last = eventlist.Dequeue(); if (!(last is EndElementEvent)) { throw ParserHelper.Error("Unexpected Event '" + last.GetType().ToString() + "', expected an EndElement Event", last); } //Now we can generate the relevant RDF INode subj, pred, obj; //Validate the Type of the Parent if (!(parent is ElementEvent)) { throw ParserHelper.Error("Unexpected Parent Event '" + parent.GetType().ToString() + "', expected an ElementEvent", parent); } ElementEvent parentEl = (ElementEvent)parent; //Get the Subject Node from the Parent subj = parentEl.SubjectNode; //Validate the ID (if any) if (!ID.Equals(String.Empty)) { this.ValidateID(context, ID, subj); } //Create a Predicate from this Element pred = this.Resolve(context, element);//context.Handler.CreateUriNode(element.QName); //Get the Object Node from the Child Node ElementEvent child = (ElementEvent)next; obj = child.SubjectNode; //Assert the Triple if (!context.Handler.HandleTriple(new Triple(subj, pred, obj))) ParserHelper.Stop(); //Add Reification where appropriate if (element.Attributes.Count == 1) { //Must be an rdf:ID attribute as we've validated this earlier //Get the Attribute Event and generate a Uri from it AttributeEvent attr = element.Attributes.First(); UriReferenceEvent uriref = new UriReferenceEvent("#" + attr.Value, attr.SourceXml); IUriNode uri = this.Resolve(context, uriref, element.BaseUri); this.Reify(context, uri, subj, pred, obj); } }
/// <summary> /// Helper function which generates standardised Error Messages /// </summary> /// <param name="message">Error Message</param> /// <param name="evt">Event causing the Error</param> /// <returns></returns> public static RdfParseException Error(String message, IRdfXmlEvent evt) { return Error(message, String.Empty, evt); }
/// <summary> /// Applies List Expansion to the given Event /// </summary> /// <param name="evt">Element to apply List Expansion to</param> /// <returns>Uri Reference for the List Item</returns> /// <remarks>List Expansion only works on Element Events</remarks> private UriReferenceEvent ListExpand(IRdfXmlEvent evt) { if (evt is ElementEvent) { //Cast to an ElementEvent ElementEvent e = (ElementEvent)evt; //Form a new Uri Reference UriReferenceEvent u = new UriReferenceEvent("rdf:_" + e.ListCounter, String.Empty); //Increment the List Counter e.ListCounter = e.ListCounter + 1; //Return the new Uri Reference return u; } else { throw ParserHelper.Error("Cannot perform List Expansion on an Event which is not an ElementEvent", evt); } }
/// <summary> /// Gets the next event from the XML stream /// </summary> /// <returns></returns> public IRdfXmlEvent GetNextEvent() { if (_stop) { return(null); } // If the Root Element is filled then return it if (_rootEl != null) { IRdfXmlEvent temp = _rootEl; _rootEl = null; return(temp); } // If Literal Parsing flag is set then we've just read an element which had rdf:parseType="Literal" if (_parseLiteral) { _requireEndElement = true; _parseLiteral = false; _noRead = true; _reader.MoveToContent(); String data = _reader.ReadInnerXml(); return(new TypedLiteralEvent(data, RdfSpecsHelper.RdfXmlLiteral, data, GetPosition())); } // If we need to return an end element then do so if (_requireEndElement) { _requireEndElement = false; _currentBaseUri = _baseUris.Pop(); return(new EndElementEvent(GetPosition())); } // If at EOF throw an error if (_reader.EOF) { throw new RdfParseException("Unable to read further events as the end of the stream has already been reached"); } // Otherwise attempt to read the next node bool read = true; if (!_noRead) { read = _reader.Read(); } else { _noRead = false; } if (read) { // Return the appropriate event for the Node Type switch (_reader.NodeType) { case XmlNodeType.Element: // Element if (_first) { _first = false; _rdfRootSeen = IsName("RDF", NamespaceMapper.RDF); _rootEl = GetElement(); RootEvent root = new RootEvent(GetBaseUri(), _reader.Value, GetPosition()); root.DocumentElement = (ElementEvent)_rootEl; root.Children.Add((ElementEvent)_rootEl); if (root.BaseUri.Equals(String.Empty)) { root.BaseUri = _currentBaseUri; } return(root); } else { if (!_first && IsName("RDF", NamespaceMapper.RDF)) { if (_rdfRootSeen) { throw new RdfParseException("Unexpected nested rdf:RDF node encountered, this is not valid RDF/XML syntax"); } _noRead = true; _first = true; return(new ClearQueueEvent()); } return(GetElement()); } case XmlNodeType.EndElement: // End of an Element _currentBaseUri = _baseUris.Pop(); if (IsName("RDF", NamespaceMapper.RDF)) { _stop = true; } return(new EndElementEvent(GetPosition())); case XmlNodeType.Attribute: // Attribute throw new RdfParseException("Unexpected Attribute Node encountered"); case XmlNodeType.Text: return(new TextEvent(_reader.Value, _reader.Value, GetPosition())); case XmlNodeType.CDATA: return(new TextEvent(_reader.Value, _reader.Value, GetPosition())); case XmlNodeType.Document: case XmlNodeType.DocumentType: case XmlNodeType.XmlDeclaration: case XmlNodeType.Comment: case XmlNodeType.ProcessingInstruction: case XmlNodeType.Notation: case XmlNodeType.Whitespace: // Node Types that don't generate events and just indicate to continue reading return(GetNextEvent()); default: throw new RdfParseException("Unexpected XML Node Type " + _reader.NodeType.ToString() + " encountered"); } } else { return(null); } }
/// <summary> /// Helper function which inserts an Element back on the front of a Queue /// </summary> /// <param name="eventlist">Queue to insert onto the Front of</param> /// <param name="evt">Event to put on the front of the Queue</param> private void QueueJump(IEventQueue<IRdfXmlEvent> eventlist, IRdfXmlEvent evt) { Stack<IRdfXmlEvent> temp = new Stack<IRdfXmlEvent>(); temp.Push(evt); while (eventlist.Count > 0) { temp.Push(eventlist.Dequeue()); } foreach (IRdfXmlEvent e in temp.Reverse()) { eventlist.Enqueue(e); } }
/// <summary> /// Adds an Event to the Queue /// </summary> /// <param name="e">Event</param> public abstract void Enqueue(IRdfXmlEvent e);
/// <summary> /// Implementation of the RDF/XML Grammar Production 'emptyPropertyElt' /// </summary> /// <param name="context">Parser Context</param> /// <param name="element">Element Event for the Empty Property Element</param> /// <param name="parent">Parent Event (ie. Node) of the Property Element</param> private void GrammarProductionEmptyPropertyElement(RdfXmlParserContext context, ElementEvent element, IRdfXmlEvent parent) { //Tracing if (this._traceparsing) { this.ProductionTrace("Empty Property Element"); } //Apply Namespaces this.ApplyNamespaces(context, element); INode subj, pred, obj; ElementEvent parentEl; //Are there any attributes OR Only a rdf:ID attribute? if (element.Attributes.Count == 0 || (element.Attributes.Count == 1 && RdfXmlSpecsHelper.IsIDAttribute(element.Attributes[0]))) { //No Attributes/Only rdf:ID //Get the Subject Node from the Parent parentEl = (ElementEvent)parent; subj = parentEl.SubjectNode; //Create the Predicate from the Element pred = this.Resolve(context, element);//context.Handler.CreateUriNode(element.QName); //Create the Object if (!element.Language.Equals(String.Empty)) { obj = context.Handler.CreateLiteralNode(String.Empty, element.Language); } else { obj = context.Handler.CreateLiteralNode(String.Empty); } //Make the Assertion if (!context.Handler.HandleTriple(new Triple(subj, pred, obj))) ParserHelper.Stop(); //Reifiy if applicable if (element.Attributes.Count == 1) { //Validate the ID this.ValidateID(context, element.Attributes[0].Value, subj); //Resolve the Uri UriReferenceEvent uriref = new UriReferenceEvent("#" + element.Attributes[0].Value, String.Empty); IUriNode uri = this.Resolve(context, uriref, element.BaseUri); this.Reify(context, uri, subj, pred, obj); } } else if (element.Attributes.Count > 0 && element.Attributes.Where(a => RdfXmlSpecsHelper.IsDataTypeAttribute(a)).Count() == 1) { //Should be processed as a Typed Literal Event instead EventQueue<IRdfXmlEvent> temp = new EventQueue<IRdfXmlEvent>(); temp.Enqueue(element); temp.Enqueue(new TextEvent(String.Empty, String.Empty)); temp.Enqueue(new EndElementEvent()); this.GrammarProductionLiteralPropertyElement(context, temp, parent); return; } else { //Check through attributes IRdfXmlEvent res = null; //Check through attributes to decide the Subject of the Triple(s) String ID = String.Empty; int limitedAttributes = 0; foreach (AttributeEvent a in element.Attributes) { if (RdfXmlSpecsHelper.IsResourceAttribute(a)) { //An rdf:resource attribute so a Uri Reference res = new UriReferenceEvent(a.Value, a.SourceXml); limitedAttributes++; } else if (RdfXmlSpecsHelper.IsNodeIDAttribute(a)) { //An rdf:nodeID attribute so a Blank Node //Validate the Node ID if (!XmlSpecsHelper.IsName(a.Value)) { //Invalid nodeID throw ParserHelper.Error("The value '" + a.Value + "' for rdf:nodeID is not valid, RDF Node IDs can only be valid Names as defined by the W3C XML Specification", "Empty Property Element", a); } res = new BlankNodeIDEvent(a.Value, a.SourceXml); limitedAttributes++; } else if (RdfXmlSpecsHelper.IsIDAttribute(a)) { //Set the ID for later use in reification ID = "#" + a.Value; } //Check we haven't got more than 1 of the Limited Attributes if (limitedAttributes > 1) { throw ParserHelper.Error("A Property Element can only have 1 of the following attributes: rdf:nodeID or rdf:resource", "Empty Property Element", element); } } if (res == null) { //No relevant attributes so an anonymous Blank Node res = new BlankNodeIDEvent(String.Empty); } //Now create the actual Subject Node if (res is UriReferenceEvent) { //Resolve the Uri Reference UriReferenceEvent uriref = (UriReferenceEvent)res; subj = this.Resolve(context, uriref, element.BaseUri); } else if (res is BlankNodeIDEvent) { BlankNodeIDEvent blank = (BlankNodeIDEvent)res; if (blank.Identifier.Equals(String.Empty)) { //Have the Graph generate a Blank Node ID subj = context.Handler.CreateBlankNode(); } else { //Use the supplied Blank Node ID subj = context.Handler.CreateBlankNode(blank.Identifier); } } else { //Should never hit this case but required to get the Code to Compile //Have the Graph generate a Blank Node ID subj = context.Handler.CreateBlankNode(); } //Validate the ID (if any) if (!ID.Equals(String.Empty)) { this.ValidateID(context, ID.Substring(1), subj); } //Relate the Property element to its parent parentEl = (ElementEvent)parent; pred = this.Resolve(context, element);//context.Handler.CreateUriNode(element.QName); if (!context.Handler.HandleTriple(new Triple(parentEl.SubjectNode, pred, subj))) ParserHelper.Stop(); //Reify if applicable if (!ID.Equals(String.Empty)) { //Resolve the Uri UriReferenceEvent uriref = new UriReferenceEvent(ID, String.Empty); IUriNode uri = this.Resolve(context, uriref, element.BaseUri); this.Reify(context, uri, parentEl.SubjectNode, pred, subj); } //Process the rest of the Attributes foreach (AttributeEvent a in element.Attributes) { if (a.QName.Equals("rdf:type")) { //A Property Attribute giving a Type //Assert a Type Triple UriReferenceEvent type = new UriReferenceEvent(a.Value, a.SourceXml); pred = context.Handler.CreateUriNode(UriFactory.Create(RdfSpecsHelper.RdfType)); obj = this.Resolve(context, type, element.BaseUri); if (!context.Handler.HandleTriple(new Triple(parentEl.SubjectNode, pred, obj))) ParserHelper.Stop(); } else if (RdfXmlSpecsHelper.IsPropertyAttribute(a)) { //A Property Attribute //Validate the Normalization of the Attribute Value #if !NO_NORM if (!a.Value.IsNormalized()) { throw ParserHelper.Error("Encountered a Property Attribute '" + a.QName + "' whose value was not correctly normalized in Unicode Normal Form C", "Empty Property Element", a); } else { #endif //Create the Predicate from the Attribute QName pred = context.Handler.CreateUriNode(UriFactory.Create(Tools.ResolveQName(a.QName, context.Namespaces, context.BaseUri))); //Create the Object from the Attribute Value if (element.Language.Equals(String.Empty)) { obj = context.Handler.CreateLiteralNode(a.Value); } else { obj = context.Handler.CreateLiteralNode(a.Value, element.Language); } //Assert the Property Triple if (!context.Handler.HandleTriple(new Triple(subj, pred, obj))) ParserHelper.Stop(); #if !NO_NORM } #endif } else if (RdfXmlSpecsHelper.IsIDAttribute(a) || RdfXmlSpecsHelper.IsNodeIDAttribute(a) || RdfXmlSpecsHelper.IsResourceAttribute(a)) { //These have already been processed //We test for them so that we can then throw ParserHelper.Errors in the final case for unexpected attributes } else { //Unexpected Attribute throw ParserHelper.Error("Unexpected Attribute '" + a.QName + "' encountered on a Property Element! Only rdf:ID, rdf:resource, rdf:nodeID and Property Attributes are permitted on Property Elements", "Empty Property Element", element); } } } }