How to add namespace to XPath in C#? - c#

I tried to parse an XML file: http://www.ikea.com/pl/pl/catalog/products/30198858?type=xml&dataset=normal,parentCategories,allImages but I obtained error
Namespace Manager or XlstContext needed. This query has a prefix, variable or user-definde function."
Code:
XPathDocument oXPathDocument = new XPathDocument(path);
XPathNavigator oXPathNameNavigator = oXPathDocument.CreateNavigator();
XPathNodeIterator oProductNodesIterator = oXPathNameNavigator.Select(#"/ikea-rest/products/product/items/item");
productModel.productName = oXPathNameNavigator.SelectSingleNode("name").Value;
I found that this error is being caused by lack of namespace so I tried to add it like this:
XmlNamespaceManager nameSpace = new XmlNamespaceManager(oXPathNameNavigator.NameTable);
nameSpace.AddNamespace("ir",path);
Now I have new error:"System.NullReferenceException: Object reference not set to an instance of an object." in line:
productModel.productName = oXPathNameNavigator.SelectSingleNode("name").Value;
What's wrong with my code?

Namespace handling always trips me up, so I had to play around for a bit to get this working right. Your big problem was that when you add a namespace, you provide the address for that namespace, not reuse the path to the xml doc itself.
XPathDocument oXPathDocument = new XPathDocument(path);
XPathNavigator oXPathNameNavigator = oXPathDocument.CreateNavigator();
XmlNamespaceManager nameSpace = new XmlNamespaceManager(oXPathNameNavigator.NameTable);
//use the namespace address provided in the XML, not the path to the xml itself
nameSpace.AddNamespace("ir","http://www.ikea.com/v1.0");
//now you have to scope your query to the namespace you just defined, otherwise xpath will assume the node is not in a namespace
productModel.productName = oXPathNameNavigator.SelectSingleNode("//ir:ikea-rest/products/product/name", nameSpace).Value;
I tested this in LinqPAD and I was able to correctly get at the node you were interested in.

Related

Parase XML data from NMAP output using c# and this persons library NmapXmlParser

The developer of this particular library seems to be MIA.
https://github.com/Kamiizumi/NmapXmlParser
To test the issue grab his library (NmapXmlParser) from Nu-Get and make sure you have
using System.Xml.Serialization;
using System.IO;
using Xunit;
The code he gives on the example looks like this
var xmlSerializer = new XmlSerializer(typeof(nmaprun));
var result = default(nmaprun);
using (var xmlStream = new StreamReader("NmapResults.xml"))
{
result = xmlSerializer.Deserialize(xmlStream) as nmaprun;
}
Console.WriteLine(result.args);
This works when getting the elements inside of the nmaprun object.
He does not give any other examples so I assumed if I wanted to check the host object i would change all instances of nmaprun in above code to host. And then on the Console line change to an element inside the host object like this
var xmlSerializer = new XmlSerializer(typeof(host));
var result = default(host);
using (var xmlStream = new StreamReader("NmapResults.xml"))
{
result = xmlSerializer.Deserialize(xmlStream) as host;
}
Console.WriteLine(result.reason);
The Intellisense inside of the Console.Writeline wants to autocomplete to the elements so I feel its set up right but I keep getting this error.
System.InvalidOperationException: 'There is an error in XML document (5, 2).'
Inner Exception InvalidOperationException: was not expected.
You can use the example XML in his Github if you do not have an Nmap xml output file

XML schema parsing from XBRL schemaRef

I'm trying to validate an XBRL document, but I'm a bit lost. The XBRL is a (simplified) example of the Dutch taxonomy for company tax submits. Here's the XBRL:
string xbrl = #"<xbrli:xbrl xml:lang='nl' xmlns:xbrli='http://www.xbrl.org/2003/instance' xmlns:link='http://www.xbrl.org/2003/linkbase' xmlns:xlink='http://www.w3.org/1999/xlink' xmlns:bd-alg='http://www.nltaxonomie.nl/8.0/basis/bd/items/bd-algemeen' xmlns:xbrldi='http://xbrl.org/2006/xbrldi' xmlns:bd-dim-dom='http://www.nltaxonomie.nl/8.0/basis/bd/domains/bd-domains' xmlns:bd-dim-dim='http://www.nltaxonomie.nl/8.0/domein/bd/axes/bd-axes' xmlns:bd-bedr='http://www.nltaxonomie.nl/8.0/basis/bd/items/bd-bedrijven' xmlns:iso4217='http://www.xbrl.org/2003/iso4217'>
<link:schemaRef xlink:type='simple' xlink:href='http://www.nltaxonomie.nl/8.0/report/bd/entrypoints/bd-rpt-vpb-aangifte-2013.xsd' xlink:arcrole='http://www.w3.org/1999/xlink/properties/linkbase'/>
<xbrli:context id='c1'>
<xbrli:entity>
<xbrli:identifier scheme='www.belastingdienst.nl/identificatie'>800030357</xbrli:identifier>
</xbrli:entity>
<xbrli:period>
<xbrli:startDate>2013-07-01</xbrli:startDate>
<xbrli:endDate>2014-06-01</xbrli:endDate>
</xbrli:period>
<xbrli:scenario>
<xbrldi:explicitMember dimension='bd-dim-dim:PartyDimension'>bd-dim-dom:Declarant</xbrldi:explicitMember>
</xbrli:scenario>
</xbrli:context>
<xbrli:context id='c2'>
<xbrli:entity>
<xbrli:identifier scheme='www.belastingdienst.nl/identificatie'>800030357</xbrli:identifier>
</xbrli:entity>
<xbrli:period>
<xbrli:instant>2014-06-01</xbrli:instant>
</xbrli:period>
<xbrli:scenario>
<xbrldi:explicitMember dimension='bd-dim-dim:TimeDimension'>bd-dim-dom:End</xbrldi:explicitMember>
<xbrldi:explicitMember dimension='bd-dim-dim:PartyDimension'>bd-dim-dom:Declarant</xbrldi:explicitMember>
</xbrli:scenario>
</xbrli:context>
<xbrli:unit id='u1'>
<xbrli:measure>iso4217:EUR</xbrli:measure>
</xbrli:unit>
<bd-alg:SoftwarePackageName contextRef='c1'>SoftwareNaame</bd-alg:SoftwarePackageName>
<bd-alg:SoftwarePackageVersion contextRef='c1'>V1</bd-alg:SoftwarePackageVersion>
<bd-alg:TaxReturnMessageType contextRef='c1'>81</bd-alg:TaxReturnMessageType>
<bd-bedr:AssetsTotalAmountFiscal contextRef='c2' decimals='INF' unitRef='u1'>0</bd-bedr:AssetsTotalAmountFiscal>
<bd-bedr:BalanceProfitCalculationForTaxPurposesFiscal contextRef='c1' decimals='INF' unitRef='u1'>0</bd-bedr:BalanceProfitCalculationForTaxPurposesFiscal>
</xbrli:xbrl>";
I use the following code to load the XSD and validate the document:
var doc = XDocument.Parse(xbrl);
var xmlReader = XmlReader.Create("http://www.nltaxonomie.nl/8.0/report/bd/entrypoints/bd-rpt-vpb-aangifte-2013.xsd");
var schema = XmlSchema.Read(xmlReader,
(sender, e) => { throw e.Exception; });
var set = new XmlSchemaSet();
set.Add(schema);
set.Compile();
doc.Validate(set, (sender, e) =>
{
throw new Exception("document validation failed: " + e.Message);
});
This produces the following error message:
document validation failed: The element 'xbrl' in namespace 'http://www.xbrl.org/2003/instance' has invalid child element 'SoftwarePackageName' in namespace 'http://www.nltaxonomie.nl/8.0/basis/bd/items/bd-algemeen'. List of possible elements expected: 'item, tuple, context, unit' in namespace 'http://www.xbrl.org/2003/instance' as well as 'footnoteLink' in namespace 'http://www.xbrl.org/2003/linkbase'.
Apparantly SchemaSet.Compile fails to find all the related XSD's (direct link to the main XSD here). I've been trying different ways of loading the schema and parsing the document for hours now, but I'm not sure how to solve this problem.
I have also tried to read the document with Gepsio. Gepsio loads the document, but doesn't find any facts in the document, so it looks like the structure of the Dutch taxonomy schema is the problem here.
Your XML instance does not validate with that schema. Perhaps it will validate with another schema which imports it, or perhaps you need to create a new schema which imports all the schemas you need.
The problem is that these elements, placed at top level below root, at the end of your file:
<bd-alg:SoftwarePackageName contextRef='c1'>SoftwareNaame</bd-alg:SoftwarePackageName>
<bd-alg:SoftwarePackageVersion contextRef='c1'>V1</bd-alg:SoftwarePackageVersion>
<bd-alg:TaxReturnMessageType contextRef='c1'>81</bd-alg:TaxReturnMessageType>
<bd-bedr:AssetsTotalAmountFiscal contextRef='c2' decimals='INF' unitRef='u1'>0</bd-bedr:AssetsTotalAmountFiscal>
<bd-bedr:BalanceProfitCalculationForTaxPurposesFiscal contextRef='c1' decimals='INF' unitRef='u1'>0</bd-bedr:BalanceProfitCalculationForTaxPurposesFiscal>
are not allowed, according to the schema.
If you believe they should be allowed, probably you are not using the correct schema.
If your application can use a derived type, a solution would be to create a new schema which imports the schema you need, and defines a new root (in a new namespace) which allows the extra elements. If the types in the original schema are exposed, you can also try to redefine the root type in the same namespace.

How to process webdav server XML request in C#

I am writing a custom WebDAV server in C#. One of the client test programs I am using is NetDrive and it claims and appears to be a WebDAV compliant client. My problem is I am receiving a request on the server in the following format:
<?xml version="1.0" encoding="utf-8"?>
<propfind xmlns="DAV:">
<allprop/>
</propfind>
But other clients do this:
<?xml version="1.0" encoding="utf-8"?>
<D:propfind xmlns:D="DAV:">
<D:allprop/>
</D:propfind>
The two different namespace formats keep on fooing up my logic to look for the "allprop" element. My code looks a bit like this:
string xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?><propfind xmlns=\"DAV:\"><allprop/></propfind>"; //Hardcode to make all the StackOverflow users' lives easier
XPathDocument doc = new XPathDocument(new StringReader(xml));
XPathNavigator nav = doc.CreateNavigator();
XPathNodeIterator it = nav.Select("/propfind/*");
Now, I know I need to put in some type of namespace manager for the "DAV:", so I tried this:
XmlNamespaceManager nsman = new XmlNamespaceManager(nav.NameTable);
nsman.AddNamespace("", "DAV");
XPathNodeIterator it = nav.Select("/propfind/*", nsman);
But I'm getting no nodes in my iterator for the first XML file. It seems the default namespace isn't working like I thought it should.
What am I doing wrong? How do I query this XML for the existence of an allprop node when the namespace may be the default, or may be explicitly named?
You are using the wrong namespace in your code. Unforunalely the WebDAV specs use
'DAV:' as the namespace for WebDAV nodes and attributes (this seems to be caused by
a missunderstanding of the XML namespace mechanism).
I ended up looking for the namespace URI (DAV:) and adding it if it didn't exist. Then I just did a namespace-qualified SELECT and it worked in all my test cases:
XPathDocument document = new XPathDocument(xml);
XPathNavigator navigator = document.CreateNavigator();
//Get namespaces & add them to the search
bool hasDAV = false;
string davPrefix = "D";
XmlNamespaceManager nsman = new XmlNamespaceManager(navigator.NameTable);
foreach (KeyValuePair<string, string> nskvp in navigator.GetNamespacesInScope(XmlNamespaceScope.All))
{
if (string.Compare(nskvp.Value, "DAV:", StringComparison.InvariantCultureIgnoreCase) == 0)
{
hasDAV = true;
davPrefix = nskvp.Key;
}
nsman.AddNamespace(nskvp.Key, nskvp.Value);
}
if (!hasDAV)
nsman.AddNamespace(davPrefix , "DAV:");
XPathNodeIterator iterator = navigator.Select("/" + davPrefix + ":" + WebDavXML.PropFind + "/*", nsman);

how to parse a XML in C# using NamspaceManager,XML is having namespaces defined at elements level

i wish to parse following XML
<?xml version="1.0" encoding="UTF-8"?>
<product xmlns="http://products.org">
<make xmlns="http://camera.org">
<model>Camry</model>
</make>
<make xmlns="http://tv.org">
<model>Sony</model>
</make>
</product>
Code written to parse it
This is how i m writing Parsing Code
but in last i m getting null inxmlNode object. Can u tell what more to do .
You can't ignore namespaces in XPath.* The elements in your document all have non-blank namespace URI's.
Your question title indicates you're on the right track: you need to explicitly bind the URI's to prefixes using an XmlNamespaceManager, and use those prefixes in your path expressions.
This program is tested against your input document
using System;
using System.Xml;
public class XPathNamespace
{
public static void Main() {
XmlDocument doc = new XmlDocument();
doc.Load("test1.xml");
XmlNamespaceManager xnm = new XmlNamespaceManager(doc.NameTable);
xnm.AddNamespace("p", "http://products.org");
xnm.AddNamespace("c", "http://camera.org");
xnm.AddNamespace("t", "http://tv.org");
ShowNode(doc.SelectSingleNode("/p:product", xnm));
ShowNode(doc.SelectSingleNode("/p:product/c:make", xnm));
ShowNode(doc.SelectSingleNode("/p:product/t:make", xnm));
}
private static void ShowNode(XmlNode node) {
Console.WriteLine("<{0}> {1}",
node.LocalName,
node.NamespaceURI);
}
}
and it produces the following output
<product> http://products.org
<make> http://camera.org
<make> http://tv.org
Hope this helps.
(*) This doesn't mean you can't ignore the exact namespace in your XPath. For example, you could match
/*[local-name()='product']
But that's a workaround and illustrates that you still have to deal with the presence of a namespace somehow or other.
This is the best example for you. Please have a look.
http://www.codeproject.com/KB/cpp/myXPath.aspx

"An object reference is required for the non-static field, method, or property"

i am stuck with this small problem in my code.
I am trying to make small console application which will write into xml document.
I have used xmldocument and xmlnode concept.
ERROR i am getting is;
*An object reference is required for the non-static field, method, or property 'Write_xml.Program.give_node(System.Xml.XmlDocument)' C:\Documents and Settings\Administrator\Desktop\Write_xml\Write_xml\Program.cs*
code is okay except 1 error. I am not able to resolve it ,i want somebody to check it and correct it.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace Write_xml
{
class Program
{
static void Main(string[] args)
{
XmlDocument doc = new XmlDocument();
XmlDocument lets = new XmlDocument();
string path = #"D:\XMLFile.xml";
doc.Load(path);
XmlNode Rootnode = doc.SelectSingleNode("Number");
XmlNode TakenOde = give_node(doc);
Rootnode.AppendChild(TakenOde);
doc.Save(path);
}
public XmlNode give_node(XmlDocument lets)
{
// On this xmldoc we will perform XMLNODE operations
// for creat new nods and append child nodes
//XmlNode RootNode = xmldoc.CreateElement("Root");
XmlNode PersonsNode = lets.CreateElement("Person");
XmlNode NameNode = lets.CreateElement("Name");
PersonsNode.AppendChild(NameNode);
NameNode.InnerText = "1st";
XmlNode AgeNode = lets.CreateElement("Age");
PersonsNode.AppendChild(AgeNode);
AgeNode.InnerText = "2nd";
XmlNode CityNode = lets.CreateElement("City");
PersonsNode.AppendChild(CityNode);
CityNode.InnerText = "3rd";
return PersonsNode;
}
}
}
please let me what small mistake i am doing.
You're trying to call an instance method, but without specifying an instance.
The simplest fix for this is to make the give_node method static.
I haven't looked at the rest of the code to see whether it's okay or not, although give_node should be called GiveNode to follow .NET naming conventions.

Categories

Resources