I am able to read XML from this service at localhost, and it looks like this:
<?xml version="1.0" encoding="utf-8"?>
<GetEventsResponse
xmlns="http://tempuri.org/">
<GetEventsResult
xmlns:d2p1="http://schemas.datacontract.org/2004/07/Zadatak3.Models"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<d2p1:Event>
<d2p1:EndDate>2022-08-02T00:00:00</d2p1:EndDate>
<d2p1:Id>1</d2p1:Id>
<d2p1:Info></d2p1:Info>
<d2p1:Name>Party u Močvari</d2p1:Name>
<d2p1:Price>50</d2p1:Price>
<d2p1:Promoter>Močvara Promotions</d2p1:Promoter>
<d2p1:StartDate>2022-08-01T00:00:00</d2p1:StartDate>
<d2p1:Type>Party</d2p1:Type>
<d2p1:Url>http://mocvara.com/event/1</d2p1:Url>
<d2p1:Venue>
<d2p1:Address>Neka adresa</d2p1:Address>
<d2p1:City>Zagreb</d2p1:City>
<d2p1:ContactName>Pero</d2p1:ContactName>
<d2p1:Country>Hrvatska</d2p1:Country>
<d2p1:Id>1</d2p1:Id>
<d2p1:Name>Močvara</d2p1:Name>
<d2p1:PostalCode>10000</d2p1:PostalCode>
</d2p1:Venue>
</d2p1:Event>
<d2p1:Event>
<d2p1:EndDate>2022-08-11T00:00:00</d2p1:EndDate>
<d2p1:Id>2</d2p1:Id>
<d2p1:Info></d2p1:Info>
<d2p1:Name>Koncert u Skwhatu</d2p1:Name>
<d2p1:Price>80</d2p1:Price>
<d2p1:Promoter>Kištra</d2p1:Promoter>
<d2p1:StartDate>2022-08-10T00:00:00</d2p1:StartDate>
<d2p1:Type>Koncert</d2p1:Type>
<d2p1:Url>http://swkwhat.com/event/2</d2p1:Url>
<d2p1:Venue>
<d2p1:Address>Viktorovac 1</d2p1:Address>
<d2p1:City>Sisak</d2p1:City>
<d2p1:ContactName>Ivica</d2p1:ContactName>
<d2p1:Country>Hrvatska</d2p1:Country>
<d2p1:Id>2</d2p1:Id>
<d2p1:Name>Skwhat</d2p1:Name>
<d2p1:PostalCode>44000</d2p1:PostalCode>
</d2p1:Venue>
</d2p1:Event>
<d2p1:Event>
<d2p1:EndDate>2022-09-04T00:00:00</d2p1:EndDate>
<d2p1:Id>3</d2p1:Id>
<d2p1:Info></d2p1:Info>
<d2p1:Name>Festival u Močvari</d2p1:Name>
<d2p1:Price>220</d2p1:Price>
<d2p1:Promoter>Čvarci</d2p1:Promoter>
<d2p1:StartDate>2022-09-01T00:00:00</d2p1:StartDate>
<d2p1:Type>Festival</d2p1:Type>
<d2p1:Url>http://mocvara.com/festival/1</d2p1:Url>
<d2p1:Venue>
<d2p1:Address>Neka adresa</d2p1:Address>
<d2p1:City>Zagreb</d2p1:City>
<d2p1:ContactName>Pero</d2p1:ContactName>
<d2p1:Country>Hrvatska</d2p1:Country>
<d2p1:Id>1</d2p1:Id>
<d2p1:Name>Močvara</d2p1:Name>
<d2p1:PostalCode>10000</d2p1:PostalCode>
</d2p1:Venue>
</d2p1:Event>
</GetEventsResult>
</GetEventsResponse>
This is the soap request that I'm sending and the app manages to read the query:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<s:Body>
<SearchXmlResponse xmlns="http://tempuri.org/">
<SearchXmlResult>/GetEventsResponse/GetEventsResult/d2p1:Event/d2p1:Name</SearchXmlResult>
</SearchXmlResponse>
</s:Body>
</s:Envelope>
But when I try to select single node, XPath returns nothing.
Code in the app looks like this:
public string SearchXml(string query)
{
//
//http://localhost:5068/EventService.asmx/
//<?xml version="1.0" encoding="utf-8"?>
//<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
//<soap:Body>
//<SearchXml xmlns="http://www.w3.org/2001/XMLSchema">
//<query>/GetEventsResponse/GetEventsResult/d2p1:Event[1]/d2p1:Name</query>
//</SearchXml>
//</soap:Body>
//</soap:Envelope>
const string serviceUrl = "http://localhost:5068/EventService.asmx/GetEvents";
XmlDocument document = new XmlDocument();
document.Load(serviceUrl);
var nsmgr = new XmlNamespaceManager(document.NameTable);
nsmgr.AddNamespace("d2p1", "http://schemas.datacontract.org/2004/07/Zadatak3.Models");
nsmgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
nsmgr.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
nsmgr.AddNamespace("xsd", "http://www.w3.org/2001/XMLSchema");
nsmgr.AddNamespace("i", "http://www.w3.org/2001/XMLSchema-instance");
try
{
XmlNode? node = document.SelectSingleNode(query, nsmgr);
if (node != null)
{
return node.InnerText;
}
else
{
return $"Data does not exist! Search term: {query}";
}
}
catch (Exception e)
{
return $"{e.Message}";
throw;
}
}
I tried different queries, selecting multiple nodes, but it does not fetch any results
CodePudding user response:
Your problem here is that the top two elements are in a default namespace xmlns="http://tempuri.org/"
:
<GetEventsResponse
xmlns=""http://tempuri.org/"">
<GetEventsResult>
<!--Contents omitted -->
</GetEventsResult>
</GetEventsResponse>
Which is semantically equivalent to e.g.:
<def:GetEventsResponse
xmlns:def=""http://tempuri.org/"">
<def:GetEventsResult>
<!--Contents omitted -->
</def:GetEventsResult>
</def:GetEventsResponse>
Thus you must add this default namespace into the XmlNamespaceManager
with some assigned prefix in order to query for these nodes by qualified name. Your caller may then use that assigned prefix in their query.
E.g. if you assign the prefix tempuri
to http://tempuri.org/
:
nsmgr.AddNamespace("tempuri", "http://tempuri.org/");
Then the following query by the caller will now work:
/tempuri:GetEventsResponse/tempuri:GetEventsResult/d2p1:Event/d2p1:Name
Alternatively, the caller's query could specify the namespace URI directly, rather than via some namespace prefix, by using the local-name()
and namespace-uri()
XPath functions:
/*[local-name() = 'GetEventsResponse' and namespace-uri() = 'http://tempuri.org/']/*[local-name() = 'GetEventsResult' and namespace-uri() = 'http://tempuri.org/']/d2p1:Event/d2p1:Name
Demo fiddle here.
Notes:
Attempting to query a node in a default namespace without using prefix by adding the default namespace to the
XmlNamespaceManager
with an empty string""
prefix seems not to work. Even if I donsmgr.AddNamespace("", "http://tempuri.org/");
Your initial query still fails.
Demo fiddle #2 here.
You might want to reconsider your API design to allow the caller to specify the namespaces they want to query, e.g. by adding a
List<SerializableKeyValuePair<string, string>> namespaces
argument to your method, whereSerializableKeyValuePair
comes from e.g. here. This makes it the responsibility of the caller to specify the namespaces correctly, rather that the responsibility of your your server-side app to hardcode all the necessary prefixes.