Having issues getting node values. Not sure why the following code is failing to do so.
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type='text/xsl' href='STIG_unclass.xsl'?>
<Benchmark xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cpe="http://cpe.mitre.org/language/2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" id="Windows_7_STIG" xml:lang="en" xsi:schemaLocation="http://checklists.nist.gov/xccdf/1.1 http://nvd.nist.gov/schema/xccdf-1.1.4.xsd http://cpe.mitre.org/dictionary/2.0 http://cpe.mitre.org/files/cpe-dictionary_2.1.xsd" xmlns="http://checklists.nist.gov/xccdf/1.1">
<status date="2015-06-16">accepted</status>
<title>Windows 7 Security Technical Implementation Guide</title>
<description>
The Windows 7 Security Technical Implementation Guide (STIG) is published as a tool to improve the security of Department of Defense (DoD) information systems. The requirements were developed from DoD consensus, as well as the Windows 7 Security Guide and security templates published by Microsoft Corporation. Comments or proposed revisions to this document should be sent via e-mail to the following address: disa.stig_spt#mail.mil.
</description>
<notice id="terms-of-use" xml:lang="en">Developed_by_DISA_for_the_DoD</notice>
<reference href="http://iase.disa.mil">
<dc:publisher>DISA, Field Security Operations</dc:publisher>
<dc:source>STIG.DOD.MIL</dc:source>
</reference>
<plain-text id="release-info">Release: 20 Benchmark Date: 24 Jul 2015</plain-text>
</Benchmark>
Sample XML File.
and the following is my code.
String Title = LoadedXML.Element("Benchmark").Attribute("id").Value;
var XMLData = LoadedXML.Element("Benchmark").Elements("plain-text")
.Single(release => release.Attribute("id").Value == "release-info").Value;
is there a way I can get multiple Node values at the same time? Like getting the Title and Release Value at once instead of having a separate one for each?
Your code is failing because your XML contains Namespace and you can't access your nodes directly. If you want to confirm this simply query LoadedXML.Elements() and examine the values in debugger, you can clearly see the namespaces there:-
So, You need to declare the namespace and use it:-
XNamespace ns = "http://checklists.nist.gov/xccdf/1.1";
If you want both vales to be fetched at once you can project it to a anonymous type like this:-
var result = LoadedXML.Root.Elements(ns + "plain-text")
.Where(x => (string)x.Attribute("id") == "release-info")
.Select(x => new
{
Title = (string)x.Document.Root.Attribute("id"),
XMLData = x.Value
}).FirstOrDefault();
This query is giving me below output:-
Linq-to-xml is generally used to query a XML to filter it's nodes and then get the desired element/values per need. It's more like querying a table with SQL.
If all/most of the XML is required as a result, then the better approach would be to deseralize the XMl into a native (C# here) object and map it to the required model object. XML can always be thought of a serialized version of an object (although it can be manually as well), and can be deserialized back to the actual object.
.Net has native support for all these, see msdn links for XML Serialization and Deserialization for details. You can write a small method to deserialize your object like this.
using System.Xml.Linq;
using System.Xml.Serialization;
public class XMLHelper
{
public T DeserializeData<T>(string data)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
StringReader reader = new StringReader(data);
var deserializedObject = serializer.Deserialize(reader);
return deserializedObject == null ? default(T) : (T)deserializedObject;
}
}
To get the string you can do like File.ReadAllText(xmlFilePath) or whatever is easier for the situation.
This will give you deseialized object of the whole XML. If you want some other transformed object, you can either manually map that, or use AutoMapper
Related
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.
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.
I have this XML document:
<?xml version="1.0" encoding="utf-8"?>
<document xmlns="file:///someurl/goes.here">
<levelone>
<leveltwo>
<title>Test Title</title>
<item>Item 1</item>
<item>Item 2</item>
<item>Item 3</item>
</leveltwo>
</levelone>
</document>
And this code:
static void Main(string[] args)
{
XmlDocument fileIn = new XmlDocument();
fileIn.Load("XMLFile1.xml");
XmlNamespaceManager nsm = new XmlNamespaceManager(fileIn.NameTable);
nsm.AddNamespace(String.Empty, "file:///someurl/goes.here");
XmlNode docElem = fileIn.DocumentElement;
string title = docElem.SelectSingleNode("levelone/leveltwo/title", nsm).InnerText;
Console.WriteLine("Title: " + title);
Console.WriteLine("Items: " + docElem.SelectNodes("//item", nsm).Count);
Environment.Exit(0);
}
If I run this, I get a NullReferenceException when I attempt to get the InnerText of the node I'm attempting to select for title. However, if I change my AddNamespace call to nsm.AddNamespace("a", "file:///someurl/goes.here") and update all of my XPaths to use that a namespace, then it works fine.
My understanding is that elements without the prefixes in an XPath refer to the empty namespace. String.Empty is said to be for the empty namespace in MSDN's docs, and I'm giving the NamespaceManager the correct namespace URI for the empty namespace. Yet it doesn't seem to be working and I find myself having to make a dummy namespace in the manager to get it to work right, which is really annoying. Why do I have to use this, or any workaround?
I am not looking for a way to get my code to run, I know of a couple ways and detailed one widely-accepted method above. I want to know why my understanding of the documentation is resulting in broken code - e.g. is this an issue on Microsoft's end or am I just misunderstanding something?
here is my xml
<?xml version="1.0" encoding="windows-1252"?>
<OpenShipments xmlns="x-schema:C:\UPSLabel\OpenShipments.xdr">
<OpenShipment ShipmentOption="" ProcessStatus="">
<ShipTo>
<CompanyOrName>DARMOT Sp. z o.o</CompanyOrName>
<Attention>DARMOT Sp. z o.o</Attention>
<Address1>Ojca Damiana Tynieckiego 46</Address1>
<Address2></Address2>
<Address3>DarÂ3owo</Address3>
<CountryTerritory>PL</CountryTerritory>
<PostalCode>76-150</PostalCode>
<CityOrTown>DarÂ3owo</CityOrTown>
<StateProvinceCounty></StateProvinceCounty>
<Telephone>943143185</Telephone>
</ShipTo>
<ShipmentInformation>
<ServiceType>UPS Standard</ServiceType>
<NumberOfPackages>1</NumberOfPackages>
<DescriptionOfGoods>Remanufactured auto parts</DescriptionOfGoods>
<BillingOption>PP</BillingOption>
</ShipmentInformation>
<Package>
<PackageType>CP</PackageType>
<Weight>1</Weight>
<Reference1>OUR:AWP0021</Reference1>
<Reference2>Job # 41149</Reference2>
<DeclaredValue>
<Amount>999</Amount>
</DeclaredValue>
</Package>
</OpenShipment>
</OpenShipments>
which i need to generate from my class through xml serialization in c#.
so please guide me how to write class structure for getting the above xml.
if one look closely my xml then there are few tag with attribute. here it is...
<OpenShipments xmlns="x-schema:C:\UPSLabel\OpenShipments.xdr">
so how write the property which will have attribute like above one ShipmentOption="" ProcessStatus="" and also please tell me how to generate xmlns like xmlns="x-schema:C:\UPSLabel\OpenShipments.xdr" with OpenShipments tag. here i have no knowledge how to handle this situation and the path in xml is not fixed...C:\UPSLabel\OpenShipments.xdr.
it will be different based on condition. so please guide me how to write class for the above xml in detail. thanks
Open up a Visual Studio command prompt. Then use the xsd.exe tool to do the job for you:
C:\work>xsd.exe test.xml
Microsoft (R) Xml Schemas/DataTypes support utility
[Microsoft (R) .NET Framework, Version 4.0.30319.1]
Copyright (C) Microsoft Corporation. All rights reserved.
Writing file 'C:\work\test.xsd'.
C:\work>xsd.exe /classes test.xsd
Microsoft (R) Xml Schemas/DataTypes support utility
[Microsoft (R) .NET Framework, Version 4.0.30319.1]
Copyright (C) Microsoft Corporation. All rights reserved.
Writing file 'C:\work\test.cs'.
where test.xml is the file you have shown in your post. As you can see this generates test.cs which will contain the class you could use to deserialize this XML to:
using (var reader = XmlReader.Create("test.xml"))
{
var serializer = new XmlSerializer(typeof(OpenShipments));
var openShipments = (OpenShipments)serializer.Deserialize(reader);
// TODO: do something with those shipments like for example shipping them :-)
}
You can use XElement class (System.Xml.Linq). Example:
XElement element = new XElement("OpenShipments");
XAttribute attribute = new XAttribute("xmlns", #"x-schema:C:\UPSLabel\OpenShipments.xdr");
element.Add(attribute);
If the path is not fixed you can do something like this:
string path = "C:\..."; // get your path here
XAttribute attribute = new XAttribute("xmlns", #"x-schema:" + path);
How can I create automatic GUI using XML file in C#?
Should I write a parser for the file and define a sort of "protocol" for the file's structure, and after the parse - create the GUI controls manually (respective to the data in the files)?
Or is there a better way? Is there a tool, or a built-in code in the .NET environment which can do that for me automatically?
(I am currently working with win forms, but I am willing to consider any other technology - as long as it's supported in MONO, since the code should be portable to Linux as well).
Glade is a RAD tool to enable quick & easy development of user interfaces for the GTK+ toolkit and the GNOME desktop environment.
The user interfaces designed in Glade are saved as XML, and by using the GtkBuilder GTK+ object these can be loaded by applications dynamically as needed.
By using GtkBuilder, Glade XML files can be used in numerous programming languages including C, C++, C#, Vala, Java, Perl, Python,and others.
I've used glade with C# and I was pleased with the result. Glade probably won't suit you directly, but you can at least borrow some ideas from it.
If you're going to use XML, then you should really know about XML schemas - these are XML files that describe the content of an XML file and DevStudio (and other editors) can read them and do autocompletion, which is useful. Also, you can validate an XML against a schema to ensure the content contains no structural errors.
Also, as Paul wrote, XAML is an XML system, but you'd need to use WPF framework to parse it.
WPF uses xml to define most things, it's known as xaml.
"Is there a tool, or a built-in code in the .NET environment which can do that for me automatically?"
There are various wrappers for .NET around XULRunner on code.google.com
Check out:
https://social.msdn.microsoft.com/Forums/en-US/554eefae-429f-495c-aee0-b2e971494ed0/how-do-i-create-a-gui-which-reads-xml-file-and-adds-controls-to-it-at-runtime?forum=csharplanguage
using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Xml.Linq;
namespace WindowsFormsApplication_DynamicGUIFromXML
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
XDocument guiConfig = XDocument.Load(#"../../Gui.xml");
foreach (XElement item in from y in guiConfig.Descendants("Item") select y)
{
Control tmp = new Control();
switch (item.Attribute("type").Value)
{
case "Button":
tmp = new Button();
break;
case "TextBox":
tmp = new TextBox();
break;
}
tmp.Name = item.Attribute("name").Value;
tmp.Text = item.Attribute("text").Value;
tmp.Location = new Point(Int32.Parse(item.Attribute("x").Value), Int32.Parse(item.Attribute("y").Value));
Controls.Add(tmp);
}
}
}
}
// ***********************************************
// Contents of Gui.xml
// ***********************************************
//<?xml version="1.0" encoding="utf-8" ?>
//<Gui>
// <Item type="Button" name="foo" text="bar" x="100" y="100" />
// <Item type="TextBox" name="foo2" text="bar2" x="200" y="200" />
//</Gui>
// ***********************************************