/// <summary> /// Internal Helper method which parses the child element of a <binding> element into an <see cref="INode">INode</see> /// </summary> /// <param name="context">Parser Context</param> /// <returns></returns> private INode ParseValue(SparqlXmlParserContext context) { if (context.Input.Name.Equals("uri")) { return context.Handler.CreateUriNode(new Uri(context.Input.ReadElementContentAsString())); } else if (context.Input.Name.Equals("literal")) { if (context.Input.AttributeCount == 0) { //Literal with no Data Type/Language Specifier return context.Handler.CreateLiteralNode(HttpUtility.HtmlDecode(context.Input.ReadInnerXml())); } else if (context.Input.AttributeCount == 1) { context.Input.MoveToNextAttribute(); if (context.Input.Name.Equals("xml:lang")) { //Language is specified String lang = context.Input.Value; context.Input.MoveToContent(); return context.Handler.CreateLiteralNode(context.Input.ReadElementContentAsString(), lang); } else if (context.Input.Name.Equals("datatype")) { //Data Type is specified String dt = context.Input.Value; context.Input.MoveToContent(); return context.Handler.CreateLiteralNode(context.Input.ReadElementContentAsString(), new Uri(dt)); } else { throw new RdfParseException("Unable to Parse a SPARQL Result Set since a <literal> element has an unknown attribute '" + context.Input.Name + "'!"); } } else { throw new RdfParseException("Unable to Parse a SPARQL Result Set since a <literal> element has too many Attributes, only 1 of 'xml:lang' or 'datatype' may be specified!"); } } else if (context.Input.Name.Equals("bnode")) { String bnodeID = context.Input.ReadElementContentAsString(); if (bnodeID.StartsWith("_:")) { return context.Handler.CreateBlankNode(bnodeID.Substring(2)); } else if (bnodeID.Contains("://")) { return context.Handler.CreateBlankNode(bnodeID.Substring(bnodeID.IndexOf("://") + 3)); } else if (bnodeID.Contains(":")) { return context.Handler.CreateBlankNode(bnodeID.Substring(bnodeID.LastIndexOf(':') + 1)); } else { return context.Handler.CreateBlankNode(bnodeID); } } else if (context.Input.Name.Equals("unbound")) { //HACK: This is a really ancient feature of the SPARQL Results XML format (from Working Draft in 2005) which we support to ensure compatability with old pre-standardisation SPARQL endpoints (like 3store based ones) context.Input.ReadInnerXml(); return null; } else { throw new RdfParseException("Unable to Parse a SPARQL Result Set since a <binding> element contains an unexpected element <" + context.Input.Name + ">!"); } }
/// <summary> /// Parses the XML Result Set format into a set of SPARQLResult objects /// </summary> /// <param name="context">Parser Context</param> private void Parse(SparqlXmlParserContext context) { try { context.Handler.StartResults(); //Get the Document Element and check it's a Sparql element if (!context.Input.Read()) throw new RdfParseException("Unable to Parse a SPARQL Result Set as it was not possible to read a document element from the input"); while (context.Input.NodeType != XmlNodeType.Element) { if (!context.Input.Read()) throw new RdfParseException("Unable to Parse a SPARQL Result Set as it was not possible to read a document element from the input"); } if (!context.Input.Name.Equals("sparql")) { throw new RdfParseException("Unable to Parse a SPARQL Result Set from the provided XML since the Document Element is not a <sparql> element!"); } //Go through it's attributes and check the Namespace is specified bool nsfound = false; if (context.Input.HasAttributes) { for (int i = 0; i < context.Input.AttributeCount; i++) { context.Input.MoveToNextAttribute(); if (context.Input.Name.Equals("xmlns")) { if (!context.Input.Value.Equals(SparqlSpecsHelper.SparqlNamespace)) { throw new RdfParseException("Unable to Parse a SPARQL Result Set since the <sparql> element has an incorrect Namespace!"); } else { nsfound = true; } } } } if (!nsfound) { throw new RdfParseException("Unable to Parse a SPARQL Result Set since the <sparql> element fails to specify the SPARQL Namespace!"); } //Get the Variables from the Header if (!context.Input.Read()) throw new RdfParseException("Unable to Parse a SPARQL Result Set as could not read a <head> element from the input"); if (!context.Input.Name.Equals("head")) { throw new RdfParseException("Unable to Parse a SPARQL Result Set since the first Child Node of the <sparql> element is not the required <head> element!"); } //Only parser <variable> and <link> elements if not an empty <head /> element if (!context.Input.IsEmptyElement) { while (context.Input.Read()) { //Stop reading when we hit the </head> if (context.Input.NodeType == XmlNodeType.EndElement && context.Input.Name.Equals("head")) break; //Looking for <variable> elements if (context.Input.Name.Equals("variable")) { //Should only have 1 attribute if (context.Input.AttributeCount != 1) { throw new RdfParseException("Unable to Parse a SPARQL Result Set since a <variable> element has too few/many attributes, only a 'name' attribute should be present!"); } else { //Add the Variable to the list context.Input.MoveToNextAttribute(); if (!context.Handler.HandleVariable(context.Input.Value)) ParserHelper.Stop(); context.Variables.Add(context.Input.Value); } } else if (context.Input.Name.Equals("link")) { //Not bothered about <link> elements } else { //Some unexpected element throw new RdfParseException("Unable to Parse a SPARQL Result Set since the <head> contains an unexpected element <" + context.Input.Name + ">!"); } } } if (!context.Input.Name.Equals("head")) { throw new RdfParseException("Unable to Parse a SPARQL Result Set as reached the end of the input before the closing </head> element was found"); } //Look at the <results> or <boolean> element if (!context.Input.Read()) throw new RdfParseException("Unable to Parse a SPARQL Result Set as could not read a <results> element from the input"); if (context.Input.Name.Equals("results")) { //Only parser <result> elements if it's not an empty <results /> element if (!context.Input.IsEmptyElement) { while (context.Input.Read()) { //Stop reading when we hit the </results> if (context.Input.NodeType == XmlNodeType.EndElement && context.Input.Name.Equals("results")) break; //Must be a <result> element if (!context.Input.Name.Equals("result")) { throw new RdfParseException("Unable to Parse a SPARQL Result Set since the <results> element contains an unexpected element <" + context.Input.Name + ">!"); } //Empty Elements generate an Empty Result if (context.Input.IsEmptyElement) { if (!context.Handler.HandleResult(new SparqlResult())) ParserHelper.Stop(); continue; } //Get the values of each Binding String var; INode value; SparqlResult result = new SparqlResult(); while (context.Input.Read()) { //Stop reading when we hit the </binding> if (context.Input.NodeType == XmlNodeType.EndElement && context.Input.Name.Equals("result")) break; //Must be a <binding> element if (!context.Input.Name.Equals("binding")) { throw new RdfParseException("Unable to Parse a SPARQL Result Set since a <result> element contains an unexpected element <" + context.Input.Name + ">!"); } //Must have only 1 attribute if (context.Input.AttributeCount != 1) { throw new RdfParseException("Unable to Parse a SPARQL Result Set since a <binding> element has too few/many attributes, only a 'name' attribute should be present!"); } //Get the Variable this is a binding for and its Value context.Input.MoveToNextAttribute(); var = context.Input.Value; if (!context.Input.Read()) throw new RdfParseException("Unable to Parse a SPARQL Result Set as reached the end of input when the contents of a <binding> element was expected"); value = this.ParseValue(context); //Check that the Variable was defined in the Header if (!context.Variables.Contains(var)) { throw new RdfParseException("Unable to Parse a SPARQL Result Set since a <binding> element attempts to bind a value to the variable '" + var + "' which is not defined in the <head> by a <variable> element!"); } //Set the Variable to the Value result.SetValue(var, value); } //Check that all Variables are bound for a given result binding nulls where appropriate foreach (String v in context.Variables) { if (!result.HasValue(v)) { result.SetValue(v, null); } } if (!context.Input.Name.Equals("result")) { throw new RdfParseException("Unable to Parse a SPARQL Result Set as reached the end of the input before a closing </result> element was found"); } //Add to results set if (!context.Handler.HandleResult(result)) ParserHelper.Stop(); } } if (!context.Input.Name.Equals("results")) { throw new RdfParseException("Unable to Parse a SPARQL Result Set as reached the end of the input before the closing </results> element was found"); } } else if (context.Input.Name.Equals("boolean")) { //Can't be any <variable> elements if (context.Variables.Count > 0) { throw new RdfParseException("Unable to Parse a SPARQL Result Set since the <boolean> element is specified but the <head> contained one/more <variable> elements which is not permitted!"); } try { //Get the value of the <boolean> element as a Boolean Boolean b = Boolean.Parse(context.Input.ReadInnerXml()); context.Handler.HandleBooleanResult(b); } catch (Exception) { throw new RdfParseException("Unable to Parse a SPARQL Result Set since the <boolean> element contained a value that could not be understood as a Boolean value!"); } } else { throw new RdfParseException("Unable to Parse a SPARQL Result Set since the second Child Node of the <sparql> element is not the required <results> or <boolean> element!"); } context.Handler.EndResults(true); } catch (RdfParsingTerminatedException) { context.Handler.EndResults(true); } catch { //Some other Error context.Handler.EndResults(false); throw; } }