/// <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> /// Checks whether an attribute is an rdf:datatype attribute /// </summary> /// <param name="attr">Attribute to Test</param> /// <returns>True if is an rdf:datatype attribute</returns> public static bool IsDataTypeAttribute(AttributeEvent attr) { //QName must be rdf:datatype if (attr.QName.Equals("rdf:datatype")) { //Must be a valid RDF Uri Reference return IsRdfUriReference(attr.Value); } else { return false; } }
/// <summary> /// Checks whether an attribute is an rdf:about attribute /// </summary> /// <param name="attr">Attribute to Test</param> /// <returns>True if is an rdf:about attribute</returns> public static bool IsAboutAttribute(AttributeEvent attr) { //QName must be rdf:id if (attr.QName.Equals("rdf:about")) { //Must be a valid RDF Uri Reference return IsRdfUriReference(attr.Value); } else { return false; } }
/// <summary> /// Checks whether an attribute is an property attribute /// </summary> /// <param name="attr">Attribute to Test</param> /// <returns>True if is an property attribute</returns> public static bool IsPropertyAttribute(AttributeEvent attr) { //QName must be a valid Property Attribute Uri //Any string value allowed so if Uri test is true then we're a property Attribute return IsPropertyAttributeURI(attr.QName); }
/// <summary> /// Checks whether an attribute is an rdf:nodeID attribute /// </summary> /// <param name="attr">Attribute to Test</param> /// <returns>True if is an rdf:nodeID attribute</returns> /// <remarks>Does some validation on ID value but other validation occurs in the <see cref="ValidateID()">ValidateID</see> method which is called at other points in the Parsing</remarks> public static bool IsNodeIDAttribute(AttributeEvent attr) { //QName must be rdf:nodeID if (attr.QName.Equals("rdf:nodeID")) { //Must be a valid RDF ID if (IsRdfID(attr.Value)) { //OK return true; } else { //Invalid RDF ID so Error throw ParserHelper.Error("The value '" + attr.Value + "' for rdf:id is not valid, RDF IDs can only be valid NCNames as defined by the W3C XML Namespaces specification", attr); } } else { return false; } }