I am getting an XML from a OAI-PMH request which contains a resumption token to get next set of records. How to get the resumption token Value and its other attributes such as completeListSize etc.
<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet type="text/xsl" href="static/style.xsl"?><OAI-PMH xmlns="http://www.openarchives.org/OAI/2.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/ http://www.openarchives.org/OAI/2.0/OAI-PMH.xsd"><responseDate>2015-06-24T16:45:25Z</responseDate>
<request verb="ListRecords" metadataPrefix="uketd_dc">http://publications.iadb.org/oai/request</request>
<ListRecords>
<record>
<header>
<identifier>oai:publications.iadb.org:11319/195</identifier>
<datestamp>2015-06-12T23:02:48Z</datestamp>
<setSpec>com_123456789_1</setSpec>
<setSpec>col_123456789_3</setSpec>
</header>
<metadata></metadata>
</record>
<resumptionToken completeListSize="6305" cursor="0">MToxMDB8Mjp8Mzp8NDp8NTp1a2V0ZF9kYw==</resumptionToken>
</ListRecords>
I tried the below code
XDocument root= XDocument .Load("http://publications.iadb.org/oai/request?verb=ListRecords&metadataPrefix=uketd_dc");
var tokenValue= root.Element("resumptionToken").Value;
Its returning object reference error.Please help.
Element returns an immediate child element. From the context of your document, the only element available to you is OAI-PMH - this is why you're getting the null reference exception.
In addition, your target element has a namespace as defined by the default namespace declaration (xmlns="...") in the root OAI-PMH element.
You can use Descendants to find any element in the document with your required name, so this short code should work:
XNamespace ns = "http://www.openarchives.org/OAI/2.0/";
var tokenValue = (string)root.Descendants(ns + "resumptionToken").Single();
Related
I have following XML:
<?xml version="1.0" encoding="utf-16"?>
<cincinnati xmlns="http://www.sesame-street.com/abc/def/1">
<cincinnatiChild xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ElementValue xmlns:a="http://schemas.data.org/2004/07/sesame-street.abc.def.ghi">
<a:someField>false</a:someField>
<a:data xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<b:KeyValueThing>
<b:Key>key1</b:Key>
<b:Value i:type="a:ArrayOfPeople">
<a:Person>
<a:firstField>
</a:firstField>
<a:dictionary>
<b:KeyValueThing>
<b:Key>ID</b:Key>
<b:Value i:type="c:long" xmlns:c="http://www.w3.org/2001/XMLSchema">000101</b:Value>
</b:KeyValueThing>
<b:KeyValueThing>
<b:Key>Name</b:Key>
<b:Value i:type="c:string" xmlns:c="http://www.w3.org/2001/XMLSchema">John</b:Value>
</b:KeyValueThing>
</a:dictionary>
</a:Person>
<a:Person>
...
<b:Value i:type="c:long" xmlns:c="http://www.w3.org/2001/XMLSchema">000102</b:Value>
...
</a:Person>
</b:Value>
</b:KeyValueThing>
</a:data>
</ElementValue>
</cincinnatiChild>
</cincinnati>
I need to get a list if ID values, e.g. 000101, 000102....
I think using XPath makes sense here but the multitude of namespaces makes it confusing (so a simple XmlNamespaceManager won't do).
Basically I need something like this (this syntax is of course not correct):
XmlDocument doc = // Load the xml
doc.DocumentElement.SelectSingleNode("/cincinati/cincinnatiChild/ElementValue/a:data/b:KeyValueThing/b:Value/a:Person/a:dictionary[b:KeyValueThing/b:Key='ID']");
also when I do doc.DocumentElement.SelectSingleNode("/cincinnati") or doc.DocumentElement.SelectSingleNode("/cincinnatiChild") I get null.
Since I'm unsure how to piece together al the helpfull advice from the comments I would like to see a working c# code line, either XmlDocument or XDocument are OK.
I also tries this before the SelectSingleNode:
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("a", "http://schemas.data.org/2004/07/sesame-street.abc.def.ghi");
nsmgr.AddNamespace("b", "http://schemas.microsoft.com/2003/10/Serialization/Arrays");
nsmgr.AddNamespace("c", "http://www.w3.org/2001/XMLSchema");
nsmgr.AddNamespace("i", "http://www.w3.org/2001/XMLSchema-instance");
nsmgr.AddNamespace("d", "http://www.sesame-street.com/abc/def/1");
You could bypass the namespace issues using the local-name()-function.
i.e.: in stead of b:KeyValueThing use *[local-name()='KeyValueThing']
a simple global XPath could look like this:
//*[local-name()='KeyValueThing'][*[local-name()='Key' and text()='ID' ]]/*[local-name()='Value']/text()
If you want to be more precise and speed up the XPath it would look like this:
/*[local-name()='cincinnati']/*[local-name()='cincinnatiChild']/*[local-name()='ElementValue']/*[local-name()='data']/*[local-name()='KeyValueThing']/*[local-name()='Value']/*[local-name()='Person']/*[local-name()='dictionary']/*[local-name()='KeyValueThing'][*[local-name()='Key' and text()='ID' ]]/*[local-name()='Value']/text()
I send some request and i get xml response sometimes i get
<?xml version="1.0" encoding="UTF-8"?>
<debt-response>
<status>0</status>
<name>ნ.ს.</name>
<schedules>
<schedule>07.07.2017 1171.8000 GEL 1</schedule>
<schedule>07.08.2017 1171.8000 GEL 1</schedule>
<schedule>07.09.2017 1171.8000 GEL 1</schedule>
</schedules>
</debt-response>
and sometimes i get
<?xml version="1.0" encoding="UTF-8"?>
<debt-response>
<status>0</status>
<name>ნ.ბ.</name>
<schedules>
<schedule>06.07.2018 1.5 GEL 1</schedule>
<debt>15.06.2018 0.97</debt>
</schedules>
</debt-response>
I am using var acc_numArray = xmlDoc.SelectNodes("/debt-response/schedules/debt"); but if no such element exists it goes in exception.
I want to get that debt if such node exists any solution ?
You could try
var debt = XDocument.Load("path to your xml").Descendants("debt").FirstOrDefault()?.Value;
which gets the first debt element and returns its value.
If you have more than one debt, the following code saves the element values in a list:
var debt = XDocument.Load("path to your xml").Descendants("debt").Select(d => d.Value).ToList();
If you are reading the xml from a stream, use XDocument.Parse("your string") instead of Load().
Note: you will need the System.Xml.Linq namespace.
Without seeing your code, I can only guess what you're doing - but one thing is certain, this line will not throw an exception if no nodes can be located by the specified XPath:
var acc_numArray = xmlDoc.SelectNodes("/debt-response/schedules/debt");
Instead, it will return an XmlNodeList with a count of zero.
I am assuming your exception is occurring when you try and access the nodelist as if it had items in it - but simply check the count and only access it if it is non-zero:
var acc_numArray = xmlDocument.SelectNodes("/debt-response/schedules/debt");
if (acc_numArray.Count > 0)
{
// Do stuff here
}
If you put an example of your actual code into the question it will be a lot easier to help you.
From last couple of days I was trying to extract err:Errors from following XML using c#
I am using UPS webs services and when I cancel pickup I am getting this XML as return
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header />
<soapenv:Body>
<soapenv:Fault>
<faultcode>Client</faultcode>
<faultstring>An exception has been raised as a result of client data.</faultstring>
<detail>
<err:Errors xmlns:err="http://www.ups.com/XMLSchema/XOLTWS/Error/v1.1">
<err:ErrorDetail>
<err:Severity>Hard</err:Severity>
<err:PrimaryErrorCode>
<err:Code>9510131</err:Code>
<err:Description>Order has already been canceled</err:Description>
</err:PrimaryErrorCode>
</err:ErrorDetail>
</err:Errors>
</detail>
</soapenv:Fault>
</soapenv:Body>
</soapenv:Envelope>
but cannot find any relevant solution.
This is what I tried:
XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(strResponse);
XmlNamespaceManager xmlnsManager = new XmlNamespaceManager(xDoc.NameTable);
xDoc.SelectSingleNode(
"soapenv:Envelope/soapenv:Body/soapenv:Fault/err:ErrorDetail",
xmlnsManager).InnerText;
It looks like the SelectSingleNode returns nothing.
You have to add the namespaces to your NamespaceManager:
xmlnsManager.AddNamespace("soapenv","http://schemas.xmlsoap.org/soap/envelope/");
xmlnsManager.AddNamespace("err","http://www.ups.com/XMLSchema/XOLTWS/Error/v1.1");
xDoc.SelectSingleNode(
"/soapenv:Envelope/soapenv:Body/soapenv:Fault/err:ErrorDetail",
xmlnsManager).InnerText;
before you call SelectSingleNode. Make sure you synchronize the namespace aliases in your namespacemanager with the alias used in your XPATH expression.
I develop WCF-client. My client should validate incoming messages.
One of the messages has the following structure:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Header>...</SOAP-ENV:Header>
<SOAP-ENV:Body>
<OpDescriptionResponse>
<Field Name="DateTime" Type="xsd:dateTime">
</OpDescriptionResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
In this case the client should validate: the field "DateTime" has type "dateTime" from namespace "http://www.w3.org/2001/XMLSchema".
This response is deserialized in structure containing array of XmlElement.
But I have an issue: after message is deserialized and I received corresponding variable, containing all Field nodes I can't determine value of prefix "xsd", i.e. if I take any elementof type XMLElement corresponding to Field node in reply and call element.GetNamespaceOfPrefix("xsd") I get empty string as result.
How can I get prefix's definitions are saved after deserialization?
Help me please to overcome this issue.
In order to influence the namespace/prefix, you need to use XmlSerializerNamespaces.
The following code provides a rough reference:
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add("prefixHere", "http://namespace.here/");
XmlSerializer tempSerializer = new XmlSerializer(messageObject.GetType());
tempSerializer.Serialize(Console.Out, messageObject, namespaces);
Regards,
I have the following xml;
<env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
<env:Header>
<mm7:TransactionID xmlns:mm7='http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-6-MM7-1-4' env:mustUnderstand='1'>6797324d</mm7:TransactionID>
</env:Header>
<env:Body>
<DeliveryReportReq xmlns='http://www.3gpp.org/ftp/Specs/archive/23_series/23.140/schema/REL-6-MM7-1-4'>
<MM7Version>6.8.0</MM7Version><MMSRelayServerID>TARAL</MMSRelayServerID>
<MessageID>T*3*T\*4\*855419761</MessageID>
<Recipient>
<RFC2822Address>+61438922562/TYPE=hidden</RFC2822Address>
</Recipient>
<Sender>
<RFC2822Address>61418225661/TYPE=hidden</RFC2822Address>
</Sender>
<Date>2011-08-15T12:57:27+10:00</Date>
<MMStatus>Retrieved</MMStatus>
<StatusText>The message was retrieved by the recipient</StatusText>
</DeliveryReportReq>
</env:Body>
</env:Envelope>
So then i have the following c# code;
XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(file);
XmlNode xNode = xDoc.SelectSingleNode("env:Envelope");
and i get the error;
Namespace Manager or XsltContext needed. This query has a prefix, variable, or user-defined function.
anyone know how to fix this?
Personally I would use LINQ to XML instead - its namespace support is far easier to get a handle on. It's not clear why you want to use XPath here anyway, given that Envelope is simply the root node - why not just ask for the root node?
However, if you really want to use XPath, you can create a new XmlNamespaceManager from the name table in the XmlDocument, register a prefix and then pass in the namespace manager to the SelectSingleNode overload which takes one.
There's some sample code in this answer but again I'd strongly urge you to consider other approaches if you can... particularly using LINQ to XML, where a search for (say) all the "env:Body" elements (only one here, but...) would look like this:
XNamespace env = "http://schemas.xmlsoap.org/soap/envelope/";
var bodies = doc.Descendants(env + "Body");