I'm trying to load some basic json-ld content as a string, but I'm not able to see the namespace prefixes that should be included.
Given the following json-ld:
{
"#context": {
"name": "http://schema.org/name",
"image": {
"#id": "http://schema.org/image",
"#type": "#id"
},
"foaf": "http://xmlns.com/foaf/0.1/"
},
"name": "Manu Sporny",
"foaf:homepage": "http://manu.sporny.org/",
"image": "http://manu.sporny.org/images/manu.png"
}
I run this against the dotnetrdf library:
void Main()
{
var targetPath = #"C:\Users\me\MinContext.json";
var jsonStr = File.ReadAllText(targetPath);
var parser = new JsonLdParser();
var store = new TripleStore();
parser.Load(store, new StringReader(jsonStr));
var g = store.Graphs.FirstOrDefault();
IUriNode rdfType = g.CreateUriNode("rdf:type");
IUriNode home = g.CreateUriNode("foaf:homepage");
}
On the last line I get this RdfException message:
The Namespace URI for the given Prefix 'foaf' is not known by the
in-scope NamespaceMapper. Did you forget to define a namespace for
this prefix?
...and if you inspect the graph namespaces (g.NamespaceMap.Prefixes) you can see that it only contains three: rdf, rdfs and xsd.
So question: how do I get the foaf prefix and namespace to load correctly?
This is based on using NuGet package version 2.6.1
Prefixes are not an inherent part of any RDF graph, they are just conventions and shortcuts so that you don't have to type the full IRI. A specific database software/implementation can have options for configuring namespaces/prefixes, but they are just for presentation.
In this case, JsonLdParser simply does not import any prefix from the source data into the graph. This is a perfectly valid behaviour, and I don't know if it can be changed. Load can also take IRdfHandlerwhich seems to be able to do something with prefixes, but creating an implementation will most likely be more difficult than simply defining the namespace yourself:
g.NamespaceMap.AddNamespace("foaf", new Uri("http://xmlns.com/foaf/0.1/"));
I'd argue this is actually the more correct option. The source document can specify foaf: to be absolutely anything, but you want this foaf: (the full meaning of a resource name comes from the IRI of its prefix, not from the prefix name itself).
The alternative to that is g.CreateUriNode(new Uri("http://xmlns.com/foaf/0.1/homepage")) which creates a completely equivalent node. Of course it is simpler to add the namespace instead of typing the full IRI every time – that's what namespaces are for.
Related
I am trying to create a signed xml detached signature file using this library: [opensbr]
I need to add an xpath filter to the TransformChain but upon calling SignedXml.ComputeSignature an exception is thrown that the namespace xbrli is not valid.
xpath: /xbrli:xbrl//*[not(local-name()='DocumentAdoptionStatus' or local-name()='DocumentAdoptionDate' and namespace-uri()='http://www.nltaxonomie.nl/8.0/basis/venj/items/bw2-data')]
constructing the transform (as per Microsoft example):
public static XmlDsigXPathTransform CreateXPathTransform(string XPathString)
{
XmlDocument doc = new XmlDocument();
XmlElement xPathElem = doc.CreateElement("XPath");
xPathElem.InnerText = XPathString;
XmlDsigXPathTransform xForm = new XmlDsigXPathTransform();
xForm.LoadInnerXml(xPathElem.SelectNodes("."));
return xForm;
}
The xpath and xml file are both valid.
How can I use namespace prefixes with XmlDsigXPathTransform?
MSDN example* suggests that you can declare namespace prefix on the XPath element :
.....
XmlElement xPathElem = doc.CreateElement("XPath");
xPathElem.SetAttribute("xmlns:xbrl", "xbrl namespace uri here");
xPathElem.InnerText = XPathString;
.....
*) See method LoadTransformByXml in Example #2
The issue here is that prefixes are only locally valid, within a limited scope. Your expression does not contain enough information to resolve your prefix to a namespace (even if it's the same as the default prefix in an XBRL document).
One solution is to "feed" the namespace mapping in code, as suggested by har07.
Another solution is to include the namespace in the complete XPath fragment, on a node level. This is what is used by the Dutch audit profession in official business register filings.
<dsig-xpath:XPath xmlns:dsig-xpath="http://www.w3.org/2002/06/xmldsig-filter2"
xmlns:xbrli="http://www.xbrl.org/2003/instance" Filter="subtract">
/xbrli:xbrl/*[localname()='DocumentAdoptionStatus' or local-name()='DocumentAdoptionDate' or local-name()='EmailAddressContact'] | //text()[normalize-space()='']
</dsig-xpath:XPath>
I'm just getting started with Roslyn scripting, and I'm having a little bit of trouble understanding how the Imports property on the ScriptOptions class works. I'm fine with the concept of importing an entire namespace, but if I add individual class names to the imports list, I can't use them in my script without fully qualifying them. For example:
Error: "CS0103: The name 'DateTime' does not exist in the current context"
var scriptOptions = ScriptOptions.Default
.WithReferences(typeof(DateTime).Assembly)
.WithImports(typeof(DateTime).FullName);
var script = CSharpScript.Create<DateTime>("DateTime.UtcNow",
scriptOptions);
var now = script.RunAsync(null, CancellationToken.None).Result;
Success: Use Fully-Qualified Type Name
var scriptOptions = ScriptOptions.Default
.WithReferences(typeof(DateTime).Assembly)
.WithImports(typeof(DateTime).FullName);
var script = CSharpScript.Create<DateTime>("System.DateTime.UtcNow",
scriptOptions);
var now = script.RunAsync(null, CancellationToken.None).Result;
Success: Import System Namespace
var scriptOptions = ScriptOptions.Default
.WithReferences(typeof(DateTime).Assembly)
.WithImports("System");
var script = CSharpScript.Create<DateTime>("DateTime.UtcNow",
scriptOptions);
var now = script.RunAsync(null, CancellationToken.None).Result;
What I'd like to do is restrict the script so that it only has access to a few types within a namespace (i.e. I don't want to make the whole of the System namespace available, but allow access to System.DateTime, System.Math, etc), but not require the script to fully-qualify these type names when they're used. I appreciate that it is also possible to add using statements to the script itself, but I'd ideally like to have the script engine take care of this for me.
I've attempted declaring aliases in the WithImports method (e.g. ScriptOptions.Default.WithImports("DateTime = System.DateTime")), but this just gives me a compilation error (CS0246: The type or namespace name 'DateTime = System' could not be found (are you missing a using directive or an assembly reference?)).
The documentation seems to be pretty thin on the ground, but the source for the ScriptImports class seems to suggest that namespaces, static classes, and aliases can all be imported. Am I doing something stupid or missing anything obvious here?
UPDATE
Thanks to Enfyve's helpful comments, I can now access static properties and methods, but I still have to use a fully-qualified name when calling constructors:
var scriptOptions = ScriptOptions.Default
.WithReferences(typeof(System.DateTime).FullName)
.WithImports("System.DateTime");
var script = CSharpScript.Create<object>("new DateTime()", scriptOptions);
// Still throws CS0246 compiler error...
var result = script.RunAsync(null, CancellationToken.None).Result.Dump();
You can access static properties and methods of a type by importing it as if it was an alias. eg: with .WithImports("System.DateTime") and then "UtcNow"
However, this isn't a true type-alias-directive (see: Issue #7451)
and so you cannot create objects in this manner.
How does XPath deal with XML namespaces?
If I use
/IntuitResponse/QueryResponse/Bill/Id
to parse the XML document below I get 0 nodes back.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<IntuitResponse xmlns="http://schema.intuit.com/finance/v3"
time="2016-10-14T10:48:39.109-07:00">
<QueryResponse startPosition="1" maxResults="79" totalCount="79">
<Bill domain="QBO" sparse="false">
<Id>=1</Id>
</Bill>
</QueryResponse>
</IntuitResponse>
However, I'm not specifying the namespace in the XPath (i.e. http://schema.intuit.com/finance/v3 is not a prefix of each token of the path). How can XPath know which Id I want if I don't tell it explicitly? I suppose in this case (since there is only one namespace) XPath could get away with ignoring the xmlns entirely. But if there are multiple namespaces, things could get ugly.
XPath 1.0/2.0
Defining namespaces in XPath (recommended)
XPath itself doesn't have a way to bind a namespace prefix with a namespace. Such facilities are provided by the hosting library.
It is recommended that you use those facilities and define namespace prefixes that can then be used to qualify XML element and attribute names as necessary.
Here are some of the various mechanisms which XPath hosts provide for specifying namespace prefix bindings to namespace URIs.
(OP's original XPath, /IntuitResponse/QueryResponse/Bill/Id, has been elided to /IntuitResponse/QueryResponse.)
C#:
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("i", "http://schema.intuit.com/finance/v3");
XmlNodeList nodes = el.SelectNodes(#"/i:IntuitResponse/i:QueryResponse", nsmgr);
Google Docs:
Unfortunately, IMPORTXML() does not provide a namespace prefix binding mechanism. See next section, Defeating namespaces in XPath, for how to use local-name() as a work-around.
Java (SAX):
NamespaceSupport support = new NamespaceSupport();
support.pushContext();
support.declarePrefix("i", "http://schema.intuit.com/finance/v3");
Java (XPath):
xpath.setNamespaceContext(new NamespaceContext() {
public String getNamespaceURI(String prefix) {
switch (prefix) {
case "i": return "http://schema.intuit.com/finance/v3";
// ...
}
});
Remember to call
DocumentBuilderFactory.setNamespaceAware(true).
See also:
Java XPath: Queries with default namespace xmlns
JavaScript:
See Implementing a User Defined Namespace Resolver:
function nsResolver(prefix) {
var ns = {
'i' : 'http://schema.intuit.com/finance/v3'
};
return ns[prefix] || null;
}
document.evaluate( '/i:IntuitResponse/i:QueryResponse',
document, nsResolver, XPathResult.ANY_TYPE,
null );
Note that if the default namespace has an associated namespace prefix defined, using the nsResolver() returned by Document.createNSResolver() can obviate the need for a customer nsResolver().
Perl (LibXML):
my $xc = XML::LibXML::XPathContext->new($doc);
$xc->registerNs('i', 'http://schema.intuit.com/finance/v3');
my #nodes = $xc->findnodes('/i:IntuitResponse/i:QueryResponse');
Python (lxml):
from lxml import etree
f = StringIO('<IntuitResponse>...</IntuitResponse>')
doc = etree.parse(f)
r = doc.xpath('/i:IntuitResponse/i:QueryResponse',
namespaces={'i':'http://schema.intuit.com/finance/v3'})
Python (ElementTree):
namespaces = {'i': 'http://schema.intuit.com/finance/v3'}
root.findall('/i:IntuitResponse/i:QueryResponse', namespaces)
Python (Scrapy):
response.selector.register_namespace('i', 'http://schema.intuit.com/finance/v3')
response.xpath('/i:IntuitResponse/i:QueryResponse').getall()
PhP:
Adapted from #Tomalak's answer using DOMDocument:
$result = new DOMDocument();
$result->loadXML($xml);
$xpath = new DOMXpath($result);
$xpath->registerNamespace("i", "http://schema.intuit.com/finance/v3");
$result = $xpath->query("/i:IntuitResponse/i:QueryResponse");
See also #IMSoP's canonical Q/A on PHP SimpleXML namespaces.
Ruby (Nokogiri):
puts doc.xpath('/i:IntuitResponse/i:QueryResponse',
'i' => "http://schema.intuit.com/finance/v3")
Note that Nokogiri supports removal of namespaces,
doc.remove_namespaces!
but see the below warnings discouraging the defeating of XML namespaces.
VBA:
xmlNS = "xmlns:i='http://schema.intuit.com/finance/v3'"
doc.setProperty "SelectionNamespaces", xmlNS
Set queryResponseElement =doc.SelectSingleNode("/i:IntuitResponse/i:QueryResponse")
VB.NET:
xmlDoc = New XmlDocument()
xmlDoc.Load("file.xml")
nsmgr = New XmlNamespaceManager(New XmlNameTable())
nsmgr.AddNamespace("i", "http://schema.intuit.com/finance/v3");
nodes = xmlDoc.DocumentElement.SelectNodes("/i:IntuitResponse/i:QueryResponse",
nsmgr)
SoapUI (doc):
declare namespace i='http://schema.intuit.com/finance/v3';
/i:IntuitResponse/i:QueryResponse
xmlstarlet:
-N i="http://schema.intuit.com/finance/v3"
XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:i="http://schema.intuit.com/finance/v3">
...
Once you've declared a namespace prefix, your XPath can be written to use it:
/i:IntuitResponse/i:QueryResponse
Defeating namespaces in XPath (not recommended)
An alternative is to write predicates that test against local-name():
/*[local-name()='IntuitResponse']/*[local-name()='QueryResponse']
Or, in XPath 2.0:
/*:IntuitResponse/*:QueryResponse
Skirting namespaces in this manner works but is not recommended because it
Under-specifies the full element/attribute name.
Fails to differentiate between element/attribute names in different
namespaces (the very purpose of namespaces). Note that this concern could be addressed by adding an additional predicate to check the namespace URI explicitly:
/*[ namespace-uri()='http://schema.intuit.com/finance/v3'
and local-name()='IntuitResponse']
/*[ namespace-uri()='http://schema.intuit.com/finance/v3'
and local-name()='QueryResponse']
Thanks to Daniel Haley for the namespace-uri() note.
Is excessively verbose.
XPath 3.0/3.1
Libraries and tools that support modern XPath 3.0/3.1 allow the specification of a namespace URI directly in an XPath expression:
/Q{http://schema.intuit.com/finance/v3}IntuitResponse/Q{http://schema.intuit.com/finance/v3}QueryResponse
While Q{http://schema.intuit.com/finance/v3} is much more verbose than using an XML namespace prefix, it has the advantage of being independent of the namespace prefix binding mechanism of the hosting library. The Q{} notation is known as Clark Notation after its originator, James Clark. The W3C XPath 3.1 EBNF grammar calls it a BracedURILiteral.
Thanks to Michael Kay for the suggestion to cover XPath 3.0/3.1's BracedURILiteral.
I use /*[name()='...'] in a google sheet to fetch some counts from Wikidata. I have a table like this
thes WD prop links items
NOM P7749 3925 3789
AAT P1014 21157 20224
and the formulas in cols links and items are
=IMPORTXML("https://query.wikidata.org/sparql?query=SELECT(COUNT(*)as?c){?item wdt:"&$B14&"[]}","//*[name()='literal']")
=IMPORTXML("https://query.wikidata.org/sparql?query=SELECT(COUNT(distinct?item)as?c){?item wdt:"&$B14&"[]}","//*[name()='literal']")
respectively. The SPARQL query happens not to have any spaces...
I saw name() used instead of local-name() in Xml Namespace breaking my xpath!, and for some reason //*:literal doesn't work.
For now we are able to create only new file or folder. And it's very annoying to write namespaces each time you create class declaration.
But is it possible to create new C# class file with auto generated appropriate namespaces inside? Or maybe some snippet there?
This extension provides a context menu button to add a new class, which will auto populate the namespace.
Visual Studio Code has changed a bit since the last answer. It now provides the variable TM_DIRECTORY in snippets, but this is an absolute path. I've submitted an enhancement request to provide a relative path that could be transformed to a namespace. But honestly, I think the above extension satisfies my needs (and the context menu is a plus)
That's currently not possible. You have no possibility to retrieve the current filename, directory or other information in a snippet declaration file for Visual Studio Code.
You could create a snippet that lets you enter a namespace and a class name. But I guess this wouldn't help you so much. Nevertheless it'd look like this:
"Namespace and class": {
"prefix": "namespaceAndClass",
"body": [
"namespace $1",
"{",
" class $2",
" {",
"",
" }",
"}"
],
"description": "Create a namespace block with a class"
}
In case you really want a snippet that fills in the correct namespace and class name based on the file path you could have a look at the OmniSharp project. This can give you an idea on how to improve the csharp-o extension in order to provide the correct data as a suggestion from within the plugin.
But I think this is a much bigger task then typing namespace and class on your own.
I have found these extensions that provide create C# class context menu option:
VS Sharper for C#
C# helper
C# Template Extensions
HelloVS - C# new file
A moderately dirty solution with the current variable and regex system of vscode is the following:
Assuming that your have all your projects in /your/projects/directory/
So project #1 is in /your/projects/directory/Project1/
And project #2 is in /your/projects/directory/Project2/
etc.
The following snippet will create a namespace implementation for all sub-directories:
Linux/ MacOS
"Namespace declaration":
{
"prefix": "name",
"description": "Creates a new namespace declaration.",
"body":
[
"namespace ${TM_DIRECTORY/^\\/your\\/projects\\/directory(\\/([^\\/]+))(\\/([^\\/]+))?(\\/([^\\/]+))?(\\/([^\\/]+))?(\\/([^\\/]+))?(\\/([^\\/]+))?(\\/([^\\/]+))?(\\/([^\\/]+))?(\\/([^\\/]+))?(\\/([^\\/]+))?/$2${3:+.}$4${5:+.}$6${7:+.}$8${9:+.}$10${11:+.}$12${13:+.}$14${15:+.}$16${17:+.}$18${19:+.}$20/gi}",
"{",
"}"
]
}
Windows
"Namespace declaration":
{
"prefix": "name",
"description": "Creates a new namespace declaration.",
"body":
[
"namespace ${TM_DIRECTORY/^c:\\\\your\\\\projects\\\\directory(\\\\([^\\\\]+))(\\\\([^\\\\]+))?(\\\\([^\\\\]+))?(\\\\([^\\\\]+))?(\\\\([^\\\\]+))?(\\\\([^\\\\]+))?(\\\\([^\\\\]+))?(\\\\([^\\\\]+))?(\\\\([^\\\\]+))?(\\\\([^\\\\]+))?/$2${3:+.}$4${5:+.}$6${7:+.}$8${9:+.}$10${11:+.}$12${13:+.}$14${15:+.}$16${17:+.}$18${19:+.}$20/gi}",
"{",
"}"
]
}
Explanation
The snippet matches your base directory and up to ten sub-directories (the first directory is mandatory (\\/([^\\/]+)), while all additional nine ones are optional (\\/([^\\/]+))?)
The namespace directive is then created with the first matched directory
For every successful additional sub-directory match, a dot . is inserted (${3:+.}) with the sub-match of that group ($4); for unsuccessful groups, no dot inserted and the sub-match is empty
Enjoy :)
Found this thread looking for the same answer.
I did not find any of the existing snippet suggestions to generate proper namespaces.
After some trial and error the closest I have gotten, using "variables" and "placeholder transformation", is:
"Namespace and Class": {
"prefix": "nclass",
"body": [
"namespace ${RELATIVE_FILEPATH/[\\\\]|\\w+\\.cs$/./g}$1",
"{",
"\tpublic class $TM_FILENAME_BASE\n\t{\n\t\t$0\n\t}",
"}"
],
"description": "Generates namespace and class name"
}
This will generate a namespace from the folder structure in the workspace, and class name using the file name.
There is however an issue with this as it will leave two trailing .. at end of namespace.
But cursor will stop there, so they can quickly be removed with a Ctrl + Backspace and then tab again to jump inside body of the class.
Use this one, first it focuses at the end of the namespace to add any additional section. Then it focuses inside the class.
"Namespace and Class": {
"prefix": "nc",
"body": [
"namespace $WORKSPACE_NAME$1\n{\n\tpublic class $TM_FILENAME_BASE\n\t{\n\t\t$2\n\t}\n}"
],
"description": "Generates namespace and class name"
}
I have this working code that will load a .cs file into the Roslyn SyntaxTree class, create a new PropertyDeclarationSyntax, insert it into the class, and re-write the .cs file. I'm doing this as a learning experience as well as some potential future ideas. I found that there doesn't really seem to be a full Roslyn API documentation anywhere and I'm unsure if I am doing this efficiently. My main concern is where I call 'root.ToFullString()' - whilst it works, is this the right way to do it?
using System.IO;
using System.Linq;
using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;
class RoslynWrite
{
public RoslynWrite()
{
const string csFile = "MyClass.cs";
// Parse .cs file using Roslyn SyntaxTree
var syntaxTree = SyntaxTree.ParseFile(csFile);
var root = syntaxTree.GetRoot();
// Get the first class from the syntax tree
var myClass = root.DescendantNodes().OfType<ClassDeclarationSyntax>().First();
// Create a new property : 'public bool MyProperty { get; set; }'
var myProperty = Syntax.PropertyDeclaration(Syntax.ParseTypeName("bool"), "MyProperty")
.WithModifiers(Syntax.Token(SyntaxKind.PublicKeyword))
.WithAccessorList(
Syntax.AccessorList(Syntax.List(
Syntax.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
.WithSemicolonToken(Syntax.Token(SyntaxKind.SemicolonToken)),
Syntax.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
.WithSemicolonToken(Syntax.Token(SyntaxKind.SemicolonToken)))));
// Add the new property to the class
var updatedClass = myClass.AddMembers(myProperty);
// Update the SyntaxTree and normalize whitespace
var updatedRoot = root.ReplaceNode(myClass, updatedClass).NormalizeWhitespace();
// Is this the way to write the syntax tree? ToFullString?
File.WriteAllText(csFile, updatedRoot.ToFullString());
}
}
Answered on the Roslyn CTP forum in this post:
That approach is generally fine, though if you are worried about allocating a string for the text of the entire file, you should probably use IText.Write(TextWriter) instead of ToFullString().
Keep in mind that it's possible to generate trees that will not round-trip through the parser. For example, if you generated something that violates precedence rules, the SyntaxTree construction APIs won't catch that.