/// <summary> /// Resolves a CURIE to a Node /// </summary> /// <param name="context">Parser Context</param> /// <param name="evalContext">Evaluation Context</param> /// <param name="curie">CURIE</param> /// <returns></returns> private INode ResolveCurie(RdfAParserContext context, RdfAEvaluationContext evalContext, String curie) { if (curie.StartsWith("_:")) { //The CURIE is for a Blank Node if (curie.Equals("_:")) { return context.Handler.CreateBlankNode("_"); } else { return context.Handler.CreateBlankNode(curie.Substring(2)); } } else { //CURIE is for a URI if (context.Syntax == RdfASyntax.RDFa_1_0) { //RDFa 1.0 if (curie.StartsWith(":")) { return context.Handler.CreateUriNode(new Uri(XHtmlVocabNamespace + curie.Substring(1))); } else if (curie.Contains(":")) { return context.Handler.CreateUriNode(new Uri(Tools.ResolveQName(curie, evalContext.NamespaceMap, evalContext.BaseUri))); } else { throw new RdfParseException("The value '" + curie + "' is not valid as a CURIE as it does not have a prefix"); } } else { //RDFa 1.1 return context.Handler.CreateUriNode(new Uri(Tools.ResolveQName(curie, evalContext.NamespaceMap, evalContext.BaseUri))); } } }
/// <summary> /// Resolves an Attribute which may be a CURIE/URI to a Node /// </summary> /// <param name="context">Parser Context</param> /// <param name="evalContext">Evaluation Context</param> /// <param name="uriref">URI/CURIE</param> /// <returns></returns> private INode ResolveUriOrCurie(RdfAParserContext context, RdfAEvaluationContext evalContext, String uriref) { try { if (uriref.StartsWith("[")) { //CURIE String curie = uriref.Substring(1, uriref.Length - 2); return this.ResolveCurie(context, evalContext, curie); } else if (this.IsCurie(evalContext, uriref)) { //CURIE return this.ResolveCurie(context, evalContext, uriref); } else { //URI return context.Handler.CreateUriNode(new Uri(Tools.ResolveUri(uriref, evalContext.BaseUri.ToSafeString()))); } } catch (RdfException) { this.OnWarning("Unable to resolve a URI or CURIE since the value '" + uriref + "' does not contain a valid URI/CURIE or it cannot be resolved to a URI given the in-scope namespace prefixes and Base URI"); return null; } }
private void Parse(RdfAParserContext context) { try { context.Handler.StartRdf(); //Setup the basic evaluation context and start processing RdfAEvaluationContext evalContext = new RdfAEvaluationContext(context.BaseUri); evalContext.NamespaceMap.AddNamespace(String.Empty, new Uri(XHtmlVocabNamespace)); //Set the Default and Local Vocabularly context.DefaultVocabulary = new XHtmlRdfAVocabulary(); evalContext.LocalVocabulary = new TermMappings(); //If there's a base element this permanently changes the Base URI HtmlNode baseEl = context.Document.DocumentNode.SelectSingleNode("/html/head/base"); if (baseEl != null) { if (baseEl.Attributes.Contains("href")) { String uri = baseEl.Attributes["href"].Value; if (uri.Contains("?")) { evalContext.BaseUri = new Uri(uri.Substring(0, uri.IndexOf('?'))); } else if (uri.Contains("#")) { evalContext.BaseUri = new Uri(uri.Substring(0, uri.IndexOf('#'))); } else { evalContext.BaseUri = new Uri(baseEl.Attributes["href"].Value); } } } //Check whether xml:base is permissible HtmlNodeCollection docTypes = context.Document.DocumentNode.SelectNodes("comment()"); if (docTypes != null) { foreach (HtmlNode docType in docTypes) { if (docType.InnerText.StartsWith("<!DOCTYPE")) { //Extract the Document Type Match dtd = Regex.Match(docType.InnerText, "\"([^\"]+)\">"); if (dtd.Success) { if (dtd.Groups[1].Value.Equals(XHtmlPlusRdfADoctype)) { //XHTML+RDFa does not permit xml:base context.XmlBaseAllowed = false; } break; } } } } //Select the Syntax Version to use context.Syntax = this._syntax; if (context.Syntax == RdfASyntax.AutoDetect || context.Syntax == RdfASyntax.AutoDetectLegacy) { HtmlNode docNode; if (context.Document.DocumentNode.Name.Equals("html")) { docNode = context.Document.DocumentNode; } else { docNode = context.Document.DocumentNode.SelectSingleNode("html"); } if (docNode != null && docNode.Attributes.Contains("version")) { String version = docNode.Attributes["version"].Value; switch (version) { case XHtmlPlusRdfA10Version: case HtmlPlusRdfA10Version: context.Syntax = RdfASyntax.RDFa_1_0; break; case XHtmlPlusRdfA11Version: case HtmlPlusRdfA11Version: context.Syntax = RdfASyntax.RDFa_1_1; break; default: if (context.Syntax == RdfASyntax.AutoDetect) { context.Syntax = RdfASyntax.RDFa_1_1; this.OnWarning("The value '" + version + "' is not a known value for the @version attribute - assuming RDFa 1.1"); } else { context.Syntax = RdfASyntax.RDFa_1_0; this.OnWarning("The value '" + version + "' is not a known value for the @version attribute - assuming RDFa 1.0"); } break; } } else if (context.Syntax == RdfASyntax.AutoDetect) { context.Syntax = RdfASyntax.RDFa_1_1; this.OnWarning("No @version attribute on document node - assuming RDFa 1.1"); } else if (context.Syntax == RdfASyntax.AutoDetectLegacy) { context.Syntax = RdfASyntax.RDFa_1_0; this.OnWarning("No @version attribute on document node - assuming RDFa 1.0"); } else { context.Syntax = RdfASyntax.RDFa_1_1; this.OnWarning("No @version attribute on document node - assuming RDFa 1.1"); } } this.ProcessElement(context, evalContext, context.Document.DocumentNode); context.Handler.EndRdf(true); } catch (RdfParsingTerminatedException) { context.Handler.EndRdf(true); //Discard this - it justs means the Handler told us to stop } catch { context.Handler.EndRdf(false); throw; } }
private void ProcessElement(RdfAParserContext context, RdfAEvaluationContext evalContext, HtmlNode currElement) { bool recurse = true, skip = false; bool rel = false, rev = false, about = false, src = false, href = false, property = false, type = false, resource = false, content = false, datatype = false; bool noDefaultNamespace = false; INode newSubj = null, currObj = null; List<IncompleteTriple> incomplete = new List<IncompleteTriple>(); List<String> inScopePrefixes = new List<string>(); Dictionary<String, Uri> hiddenPrefixes = null; String lang = evalContext.Language; Uri oldBase = evalContext.BaseUri; bool baseChanged = false; String oldLang = lang; bool langChanged = false; String baseUri = (evalContext.BaseUri == null) ? String.Empty : evalContext.BaseUri.ToString(); #region Steps 2-5 of the RDFa Processing Rules //Locate namespaces and other relevant attributes foreach (HtmlAttribute attr in currElement.Attributes) { String uri; if (attr.Name.StartsWith("xmlns:")) { uri = Tools.ResolveUri(attr.Value, baseUri); if (!(uri.EndsWith("/") || uri.EndsWith("#"))) uri += "#"; String prefix = attr.Name.Substring(attr.Name.IndexOf(':') + 1); if (evalContext.NamespaceMap.HasNamespace(prefix)) { if (hiddenPrefixes == null) hiddenPrefixes = new Dictionary<string, Uri>(); hiddenPrefixes.Add(prefix, evalContext.NamespaceMap.GetNamespaceUri(prefix)); } evalContext.NamespaceMap.AddNamespace(prefix, new Uri(uri)); inScopePrefixes.Add(prefix); } else { switch (attr.Name) { case "xml:lang": case "lang": //@lang and @xml:lang have the same affect if (!langChanged) { oldLang = lang; lang = attr.Value; langChanged = true; } break; case "xml:base": //@xml:base may be permitted in some cases if (context.XmlBaseAllowed) { baseUri = Tools.ResolveUri(attr.Value, baseUri); if (!(baseUri.EndsWith("/") || baseUri.EndsWith("#"))) baseUri += "#"; oldBase = evalContext.BaseUri; baseChanged = true; evalContext.BaseUri = new Uri(baseUri); } break; case "xmlns": //Can use @xmlns to override the default namespace uri = attr.Value; if (!(uri.EndsWith("/") || uri.EndsWith("#"))) uri += "#"; if (evalContext.NamespaceMap.HasNamespace(String.Empty)) { if (hiddenPrefixes == null) hiddenPrefixes = new Dictionary<string, Uri>(); hiddenPrefixes.Add(String.Empty, evalContext.NamespaceMap.GetNamespaceUri(String.Empty)); } evalContext.NamespaceMap.AddNamespace(String.Empty, new Uri(uri)); inScopePrefixes.Add(String.Empty); noDefaultNamespace = true; break; case "prefix": //Can use @prefix to set multiple namespaces with one attribute if (context.Syntax == RdfASyntax.RDFa_1_0) { this.OnWarning("Cannot use the @prefix attribute to define prefixes in RDFa 1.0"); } else { this.ParsePrefixAttribute(context, evalContext, attr, baseUri, hiddenPrefixes, inScopePrefixes); } break; case "rel": rel = true; break; case "rev": rev = true; break; case "about": about = true; break; case "src": src = true; break; case "href": href = true; break; case "resource": resource = true; break; case "typeof": type = true; break; case "content": content = true; break; case "datatype": datatype = true; break; case "property": property = true; break; case "profile": if (context.Syntax == RdfASyntax.RDFa_1_0) { this.OnWarning("Cannot use the @profile attribute in RDFa 1.0"); } else { if (this.ParseProfileAttribute(context, evalContext, attr)) { foreach (KeyValuePair<String, String> ns in evalContext.LocalVocabulary.Namespaces) { uri = Tools.ResolveUri(ns.Value, baseUri); if (!(uri.EndsWith("/") || uri.EndsWith("#"))) uri += "#"; if (evalContext.NamespaceMap.HasNamespace(ns.Key)) { if (hiddenPrefixes == null) hiddenPrefixes = new Dictionary<string, Uri>(); hiddenPrefixes.Add(ns.Key, evalContext.NamespaceMap.GetNamespaceUri(ns.Key)); } evalContext.NamespaceMap.AddNamespace(ns.Key, new Uri(uri)); inScopePrefixes.Add(ns.Key); } } else { this.OnWarning("Unable to resolve a Profile document specified by the @profile attribute on the element <" + currElement.Name + "> - ignoring the DOM subtree of this element"); return; } } break; case "vocab": if (context.Syntax == RdfASyntax.RDFa_1_0) { this.OnWarning("Cannot use the @vocab attribute in RDFa 1.0"); } else { this.ParseVocabAttribute(context, evalContext, attr); } break; } } } #endregion #region Steps 6-7 of the RDFa Processing Rules //If we hit an invalid CURIE/URI at any point then ResolveUriOrCurie will return a null and //later processing steps will be skipped for this element //Calls to Tools.ResolveUri which error will still cause the parser to halt if (!rel && !rev) { //No @rel or @rev attributes if (about && !currElement.Attributes["about"].Value.Equals("[]")) { //New Subject is the URI newSubj = this.ResolveUriOrCurie(context, evalContext, currElement.Attributes["about"].Value); } else if (src) { //New Subject is the URI newSubj = context.Handler.CreateUriNode(new Uri(Tools.ResolveUri(currElement.Attributes["src"].Value, baseUri))); } else if (resource && !currElement.Attributes["resource"].Value.Equals("[]")) { //New Subject is the URI newSubj = this.ResolveUriOrCurie(context, evalContext, currElement.Attributes["resource"].Value); } else if (href) { //New Subject is the URI newSubj = context.Handler.CreateUriNode(new Uri(Tools.ResolveUri(currElement.Attributes["href"].Value, baseUri))); } else if (currElement.Name.Equals("head") || currElement.Name.Equals("body")) { //New Subject is the Base URI try { newSubj = context.Handler.CreateUriNode(new Uri(Tools.ResolveUri(String.Empty, baseUri))); } catch (RdfException) { if (baseUri.Equals(String.Empty)) { this.OnWarning("Unable to generate a valid Subject for a Triple since the Base URI should be used but there is no in-scope Base URI"); newSubj = null; } else { throw; } } } else if (type) { //New Subject is a Blank Node newSubj = context.Handler.CreateBlankNode(); } else if (evalContext.ParentObject != null) { //New Subject is the Parent Object and will skip if no property attributes newSubj = evalContext.ParentObject; if (!property) skip = true; } } else { //A @rel or @rev attribute was encountered //For this we first set the Subject if (about && !currElement.Attributes["about"].Value.Equals("[]")) { //New Subject is the URI newSubj = this.ResolveUriOrCurie(context, evalContext, currElement.Attributes["about"].Value); } else if (src) { //New Subject is the URI newSubj = context.Handler.CreateUriNode(new Uri(Tools.ResolveUri(currElement.Attributes["src"].Value, baseUri))); } else if (currElement.Name.Equals("head") || currElement.Name.Equals("body")) { //New Subject is the Base URI try { newSubj = context.Handler.CreateUriNode(new Uri(Tools.ResolveUri(String.Empty, baseUri))); } catch (RdfException) { if (baseUri.Equals(String.Empty)) { this.OnWarning("Unable to generate a valid Subject for a Triple since the Base URI should be used but there is no in-scope Base URI"); newSubj = null; } else { throw; } } } else if (type) { //New Subject is a Blank Node newSubj = context.Handler.CreateBlankNode(); } else if (evalContext.ParentObject != null) { //New Subject is the Parent Object and will skip if no property attributes newSubj = evalContext.ParentObject; } //Then we set the Object as well if (resource && !currElement.Attributes["resource"].Value.Equals("[]")) { //New Object is the URI currObj = this.ResolveUriOrCurie(context, evalContext, currElement.Attributes["resource"].Value); } else if (href) { //New Object is the URI currObj = context.Handler.CreateUriNode(new Uri(Tools.ResolveUri(currElement.Attributes["href"].Value, baseUri))); } } #endregion #region Step 8 of the RDFa Processing Rules //If the Subject is not a null then we'll generate type triples if there's any @typeof attributes if (newSubj != null) { INode rdfType = context.Handler.CreateUriNode(new Uri(RdfSpecsHelper.RdfType)); if (type) { foreach (INode dtObj in this.ParseComplexAttribute(context, evalContext, currElement.Attributes["typeof"].Value)) { if (!context.Handler.HandleTriple(new Triple(newSubj, rdfType, dtObj))) ParserHelper.Stop(); } } } #endregion #region Steps 9-10 of the RDFa Processing Rules //If the Object is not null we'll generate triples if (newSubj != null && currObj != null) { //We can generate some complete triples if (rel) { foreach (INode pred in this.ParseComplexAttribute(context, evalContext, currElement.Attributes["rel"].Value)) { if (!context.Handler.HandleTriple(new Triple(newSubj, pred, currObj))) ParserHelper.Stop(); } } if (rev) { foreach (INode pred in this.ParseComplexAttribute(context, evalContext, currElement.Attributes["rev"].Value)) { if (!context.Handler.HandleTriple(new Triple(currObj, pred, newSubj))) ParserHelper.Stop(); } } } else { //We can generate some incomplete triples bool preds = false; if (rel) { foreach (INode pred in this.ParseComplexAttribute(context, evalContext, currElement.Attributes["rel"].Value)) { preds = true; incomplete.Add(new IncompleteTriple(pred, IncompleteTripleDirection.Forward)); } } if (rev) { foreach (INode pred in this.ParseComplexAttribute(context, evalContext, currElement.Attributes["rev"].Value)) { preds = true; incomplete.Add(new IncompleteTriple(pred, IncompleteTripleDirection.Reverse)); } } if (preds) { //Current Object becomes a Blank Node only if there were predicates currObj = context.Handler.CreateBlankNode(); } } #endregion #region Step 11 of the RDFa Processing Rules //Get the Current Object Literal if (newSubj != null && property) { //We only look for this if there is a property attribute INode currLiteral = null; Uri dt; INode dtNode = null; if (datatype && !currElement.Attributes["datatype"].Value.Equals(String.Empty)) { //Some kind of Typed Literal //Resolve the Datatype attribute into URIs try { dtNode = this.ResolveTermOrCurieOrUri(context, evalContext, currElement.Attributes["datatype"].Value); } catch (RdfException) { this.OnWarning("Unable to resolve a valid Datatype for the Literal since the value '" + currElement.Attributes["datatype"].Value + "' is not a valid CURIE or it cannot be resolved into a URI given the in-scope namespace prefixes and Base URI - assuming a Plain Literal instead"); } } if (dtNode != null) { //We can only process this Triple if we were able to get a valid URI Node for the Datatype if (dtNode.NodeType != NodeType.Uri) throw new RdfParseException("Cannot use a non-URI Node as a Dataype"); dt = ((IUriNode)dtNode).Uri; if (!dt.ToString().Equals(RdfSpecsHelper.RdfXmlLiteral)) { //There's a Datatype and it's not XML Literal if (content) { //Content attribute is used as the value currLiteral = context.Handler.CreateLiteralNode(currElement.Attributes["content"].Value, dt); } else { //Value is concatentation of child text nodes StringBuilder lit = new StringBuilder(); foreach (HtmlNode n in currElement.ChildNodes) { this.GrabText(lit, n); } currLiteral = context.Handler.CreateLiteralNode(HttpUtility.HtmlDecode(lit.ToString()), dt); } } else if (context.Syntax == RdfASyntax.RDFa_1_0) { //It's an XML Literal - this is now RDFa 1.0 Only //This is an incompatability with RDFa 1.1 foreach (HtmlNode child in currElement.ChildNodes) { this.ProcessXmlLiteral(evalContext, child, noDefaultNamespace); } currLiteral = context.Handler.CreateLiteralNode(currElement.InnerHtml, dt); } else if (context.Syntax == RdfASyntax.RDFa_1_1) { //For RDFa 1.1 we now treat as a plain literal instead //Setting this to null forces us to go into the if that processes plain literals dtNode = null; } } if (dtNode == null) { //A Plain Literal if (content) { //Content attribute is used as the value currLiteral = context.Handler.CreateLiteralNode(currElement.Attributes["content"].Value, lang); } else if (!currElement.HasChildNodes) { //Value is content of the element (if any) currLiteral = context.Handler.CreateLiteralNode(HttpUtility.HtmlDecode(currElement.InnerText), lang); } else if (currElement.ChildNodes.All(n => n.NodeType == HtmlNodeType.Text)) { //Value is concatenation of all Text Child Nodes StringBuilder lit = new StringBuilder(); foreach (HtmlNode n in currElement.ChildNodes) { if (n.NodeType == HtmlNodeType.Text) { lit.Append(n.InnerText); } } currLiteral = context.Handler.CreateLiteralNode(HttpUtility.HtmlDecode(lit.ToString()), lang); } else if (!datatype || (datatype && currElement.Attributes["datatype"].Equals(String.Empty))) { //Value is an XML Literal foreach (HtmlNode child in currElement.ChildNodes) { this.ProcessXmlLiteral(evalContext, child, noDefaultNamespace); } currLiteral = context.Handler.CreateLiteralNode(currElement.InnerHtml, new Uri(RdfSpecsHelper.RdfXmlLiteral)); } } //Get the Properties which we are connecting this literal with if (currLiteral != null) { foreach (INode pred in this.ParseAttribute(context, evalContext, currElement.Attributes["property"].Value)) { if (!context.Handler.HandleTriple(new Triple(newSubj, pred, currLiteral))) ParserHelper.Stop(); } } } #endregion #region Step 12 of the RDFa Processing Rules //Complete incomplete Triples if this is possible if (!skip && newSubj != null && evalContext.ParentSubject != null) { foreach (IncompleteTriple i in evalContext.IncompleteTriples) { if (i.Direction == IncompleteTripleDirection.Forward) { if (!context.Handler.HandleTriple(new Triple(evalContext.ParentSubject, i.Predicate, newSubj))) ParserHelper.Stop(); } else { if (!context.Handler.HandleTriple(new Triple(newSubj, i.Predicate, evalContext.ParentSubject))) ParserHelper.Stop(); } } } #endregion #region Step 13 of the RDFa Processing Rules //Recurse if necessary if (recurse) { if (currElement.HasChildNodes) { //Generate the new Evaluation Context (if applicable) RdfAEvaluationContext newEvalContext; if (skip) { newEvalContext = evalContext; newEvalContext.Language = lang; } else { Uri newBase = (baseUri.Equals(String.Empty)) ? null : new Uri(baseUri); newEvalContext = new RdfAEvaluationContext(newBase, evalContext.NamespaceMap); //Set the Parent Subject for the new Context if (newSubj != null) { newEvalContext.ParentSubject = newSubj; } else { newEvalContext.ParentSubject = evalContext.ParentSubject; } //Set the Parent Object for the new Context if (currObj != null) { newEvalContext.ParentObject = currObj; } else if (newSubj != null) { newEvalContext.ParentObject = newSubj; } else { newEvalContext.ParentObject = evalContext.ParentSubject; } newEvalContext.IncompleteTriples.AddRange(incomplete); newEvalContext.Language = lang; } newEvalContext.LocalVocabulary = new TermMappings(evalContext.LocalVocabulary); //Iterate over the Nodes foreach (HtmlNode n in currElement.ChildNodes) { if (n.NodeType == HtmlNodeType.Element) { this.ProcessElement(context, newEvalContext, n); } } } } #endregion //Now any in-scope prefixes go out of scope foreach (String prefix in inScopePrefixes) { evalContext.NamespaceMap.RemoveNamespace(prefix); //If they were hiding another prefix then that comes back into scope if (hiddenPrefixes != null) { if (hiddenPrefixes.ContainsKey(prefix)) { evalContext.NamespaceMap.AddNamespace(prefix, hiddenPrefixes[prefix]); } } } //And the Base URI resets if it was changed if (baseChanged) { evalContext.BaseUri = oldBase; } //And the Language resets if it was changed if (langChanged) { evalContext.Language = oldLang; } }
private void ParseVocabAttribute(RdfAParserContext context, RdfAEvaluationContext evalContext, HtmlAttribute attr) { if (attr.Value.Equals(String.Empty)) { //Reset Local Vocabulary evalContext.LocalVocabulary = new TermMappings(context.DefaultVocabulary); } else { evalContext.LocalVocabulary.VocabularyUri = attr.Value; } }
/// <summary> /// Parses RDFa by extracting it from the HTML from the given input /// </summary> /// <param name="handler">RDF Handler to use</param> /// <param name="input">Input to read from</param> public void Load(IRdfHandler handler, TextReader input) { if (handler == null) throw new RdfParseException("Cannot read RDF into a null RDF Handler"); if (input == null) throw new RdfParseException("Cannot read RDF from a null TextReader"); try { HtmlDocument doc = new HtmlDocument(); doc.Load(input); RdfAParserContext context = new RdfAParserContext(handler, doc); this.Parse(context); } catch { throw; } finally { try { input.Close(); } catch { //Catch is just here in case something goes wrong with closing the stream //This error can be ignored } } }
private bool ParseProfileAttribute(RdfAParserContext context, RdfAEvaluationContext evalContext, HtmlAttribute attr) { String[] profiles; if (attr.Value.Contains(" ")) { profiles = attr.Value.Split(' '); } else { profiles = new String[] { attr.Value }; } String prefixQuery = "PREFIX rdfa: <" + RdfANamespace + "> SELECT SAMPLE(?prefix) AS ?NamespacePrefix SAMPLE(?uri) AS ?NamespaceURI WHERE { ?s rdfa:prefix ?prefix ; rdfa:uri ?uri } GROUP BY ?s HAVING (COUNT(?prefix) = 1 && COUNT(?uri) = 1)"; String termQuery = "PREFIX rdfa: <" + RdfANamespace + "> SELECT SAMPLE(?term) AS ?Term SAMPLE(?uri) AS ?URI WHERE {?s rdfa:term ?term ; rdfa:uri ?uri } GROUP BY ?s HAVING (COUNT(?term) = 1 && COUNT(?uri) = 1)"; foreach (String profile in profiles) { try { Graph g = new Graph(); if (profile.Equals(XHtmlVocabNamespace) || profile.Equals(XHtmlVocabNamespace.Substring(0, XHtmlVocabNamespace.Length-1))) { //XHTML Vocabulary is a fixed vocabulary evalContext.LocalVocabulary.Merge(new XHtmlRdfAVocabulary()); } else { try { UriLoader.Load(g, new Uri(profile)); } catch { //If we fail then we return false which indicates that the DOM subtree is ignored this.OnWarning("Unable to retrieve a Profile document which the library could parse from the URI '" + profile + "'"); return false; } //Namespace Mappings Object results = g.ExecuteQuery(prefixQuery); if (results is SparqlResultSet) { SparqlResultSet rset = (SparqlResultSet)results; foreach (SparqlResult r in rset.Results) { INode prefixNode = r["NamespacePrefix"]; INode nsNode = r["NamespaceURI"]; if (prefixNode.NodeType == NodeType.Literal && nsNode.NodeType == NodeType.Literal) { String prefix = ((ILiteralNode)prefixNode).Value.ToLower(); String ns = ((ILiteralNode)nsNode).Value; evalContext.LocalVocabulary.AddNamespace(prefix, ns); } } } //Term Mappings results = g.ExecuteQuery(termQuery); if (results is SparqlResultSet) { SparqlResultSet rset = (SparqlResultSet)results; foreach (SparqlResult r in rset.Results) { INode termNode = r["Term"]; INode uriNode = r["URI"]; if (termNode.NodeType == NodeType.Literal && uriNode.NodeType == NodeType.Literal) { String term = ((ILiteralNode)termNode).Value; String uri = ((ILiteralNode)uriNode).Value; evalContext.LocalVocabulary.AddTerm(term, uri); } } } } } catch { //Ignore errors and continue processing this.OnWarning("Ignoring the value '" + profile + "' since this is not a valid URI or a profile document was not successfully retrieved and parsed from this URI"); return false; } } return true; }
private void ParsePrefixAttribute(RdfAParserContext context, RdfAEvaluationContext evalContext, HtmlAttribute attr, String baseUri, Dictionary<string,Uri> hiddenPrefixes, List<String> inScopePrefixes) { //Do nothing if the @prefix attribute is empty if (attr.Value.Equals(String.Empty)) return; StringReader reader = new StringReader(attr.Value); char next; bool canExit = false; do { StringBuilder prefixData = new StringBuilder(); StringBuilder uriData = new StringBuilder(); //Grab a Prefix - characters up to the next colon next = (char)reader.Peek(); while (next != ':') { //Add the Character and discard it prefixData.Append(next); reader.Read(); if (reader.Peek() == -1) { this.OnWarning("Aborted parsing a prefix attribute since failed to find a prefix of the form prefix: from the following content: " + prefixData.ToString()); return; } else { next = (char)reader.Peek(); } } //Discard the colon reader.Read(); //Discard the whitespace next = (char)reader.Peek(); while (Char.IsWhiteSpace(next)) { reader.Read(); if (reader.Peek() == -1) { this.OnWarning("Aborted parsing a prefix attribute since reached the end of the attribute without finding a URI to go with the prefix '" + prefixData.ToString() + ":'"); return; } else { next = (char)reader.Peek(); } } //Grab the URI - characters up to the next whitespace or end of string next = (char)reader.Peek(); while (!Char.IsWhiteSpace(next)) { uriData.Append(next); reader.Read(); if (reader.Peek() == -1) { //End of string so will exit after this canExit = true; break; } else { next = (char)reader.Peek(); } } //Now resolve the URI and apply it String uri = Tools.ResolveUri(uriData.ToString(), baseUri); if (!(uri.EndsWith("/") || uri.EndsWith("#"))) uri += "#"; String prefix = prefixData.ToString(); if (evalContext.NamespaceMap.HasNamespace(prefix)) { if (hiddenPrefixes == null) hiddenPrefixes = new Dictionary<string, Uri>(); hiddenPrefixes.Add(prefix, new Uri(uri)); } evalContext.NamespaceMap.AddNamespace(prefix, new Uri(uri)); inScopePrefixes.Add(prefix); } while (!canExit); }
/// <summary> /// Parses an attribute into a number of Nodes from the CURIEs contained in the Attribute /// </summary> /// <param name="context">Parser Context</param> /// <param name="evalContext">Evaluation Context</param> /// <param name="value">Attribute Value</param> /// <returns></returns> private List<INode> ParseAttribute(RdfAParserContext context, RdfAEvaluationContext evalContext, String value) { List<INode> nodes = new List<INode>(); String[] values; if (value.Contains(" ")) { values = value.Split(' '); } else { values = new String[] { value }; } foreach (String val in values) { try { INode n = this.ResolveCurie(context, evalContext, val); nodes.Add(n); } catch { //Errors are ignored, they don't produce a URI //Raise a warning anyway this.OnWarning("Ignoring the value '" + val + "' since this is not a valid CURIE or it cannot be resolved into a URI given the in-scope Namespace Prefixes and Base URI"); } } return nodes; }
private INode ResolveTermOrCurieOrUri(RdfAParserContext context, RdfAEvaluationContext evalContext, String value) { if (this.IsTerm(value)) { return this.ResolveTermOrCurie(context, evalContext, value); } else if (this.IsCurie(evalContext, value)) { return this.ResolveCurie(context, evalContext, value); } else { return context.Handler.CreateUriNode(new Uri(Tools.ResolveUri(value, evalContext.BaseUri.ToSafeString()))); } }
/// <summary> /// Resolves an Attribute which may be a Term/CURIE/URI to a Node where one/more of the values may be special values permissible in a complex attribute /// </summary> /// <param name="context">Parser Context</param> /// <param name="evalContext">Evaluation Context</param> /// <param name="curie">URI/CURIE/Term</param> /// <returns></returns> private INode ResolveTermOrCurie(RdfAParserContext context, RdfAEvaluationContext evalContext, String curie) { if (context.Syntax == RdfASyntax.RDFa_1_0) { //RDFa 1.0 XHtmlRdfAVocabulary vocab = new XHtmlRdfAVocabulary(); if (curie.StartsWith(":")) { return context.Handler.CreateUriNode(new Uri(vocab.ResolveTerm(curie.Substring(1)))); } else if (curie.Contains(":")) { return this.ResolveCurie(context, evalContext, curie); } else { if (vocab.HasTerm(curie)) { return context.Handler.CreateUriNode(new Uri(vocab.ResolveTerm(curie))); } else { throw new RdfParseException("Cannot use an unprefixed CURIE in RDFa 1.0 - only reserved XHTML terms are permitted"); } } } else { //RDFa 1.1 if (curie.StartsWith(":")) { if (evalContext.LocalVocabulary != null) { if (evalContext.LocalVocabulary.HasTerm(curie.Substring(1)) || !evalContext.LocalVocabulary.VocabularyUri.Equals(String.Empty)) { return context.Handler.CreateUriNode(new Uri(evalContext.LocalVocabulary.ResolveTerm(curie.Substring(1)))); } else if (context.DefaultVocabulary != null && context.DefaultVocabulary.HasTerm(curie.Substring(1))) { return context.Handler.CreateUriNode(new Uri(context.DefaultVocabulary.ResolveTerm(curie.Substring(1)))); } else { return this.ResolveCurie(context, evalContext, curie); } } else if (context.DefaultVocabulary != null && context.DefaultVocabulary.HasTerm(curie.Substring(1))) { return context.Handler.CreateUriNode(new Uri(context.DefaultVocabulary.ResolveTerm(curie.Substring(1)))); } else { return this.ResolveCurie(context, evalContext, curie); } } else { if (evalContext.LocalVocabulary != null) { if (evalContext.LocalVocabulary.HasTerm(curie) || !evalContext.LocalVocabulary.VocabularyUri.Equals(String.Empty)) { return context.Handler.CreateUriNode(new Uri(evalContext.LocalVocabulary.ResolveTerm(curie))); } else if (context.DefaultVocabulary != null && context.DefaultVocabulary.HasTerm(curie)) { return context.Handler.CreateUriNode(new Uri(context.DefaultVocabulary.ResolveTerm(curie))); } else { throw new RdfParseException("Unable to resolve a Term since there is no appropriate Local/Default Vocabulary in scope"); } } else if (context.DefaultVocabulary != null) { return context.Handler.CreateUriNode(new Uri(context.DefaultVocabulary.ResolveTerm(curie))); } else { throw new RdfParseException("Unable to resolve a Term since there is no appropriate Local/Default Vocabularly in scope"); } } } }