Reputation: 21
Is it possible to use XQUERY to retrieve the attributes filename
from the following XML? I am trying to use /preFileDoc/inpXML/@filename
but it doesn't work...
<?xml version="1.0"?>
<preFileDoc xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<senderId>ABC</senderId>
<receiverId>XYZ</receiverId>
<tranxCode>A001</tranxCode>
<inpXML version="1.0" encoding="UTF-8">
<soap-env:Envelope>
<soap-env:Header msgcode="SPPCONVAKT" orig-system="002FTB" refid="65355ff50a172064484bf9da64c1e245" timestamp="2009-02-11 21:00:10.741" filename="SPPCONVAKT20090128001.dat"/>
<soap-env:Body>
text1
text2
</soap-env:Body>
</soap-env:Envelope>
</inpXML>
</preFileDoc>
ps: Sometimes the filename
attributes is sent as fileName
in the incoming XML..thinking to retrieve value from attributes @filename
OR @fileName
.. can it achieve in single XQUERY? Thanks for advice...
Upvotes: 2
Views: 2326
Reputation: 4241
I think your XPath is incomplete. The last child-step /
in /preFileDoc/inpXML/@filename
only matches attributes of the inpXML
element, not its descendants.
One way to solve the problem would be the //
-step:
/preFileDoc/inpXML//@filename
Note that this would find all attributes named filename
in the soapenv:Body
, too.
A more robust way would thus be to declare the soapenv
prefix in the XQuery:
declare namespace soap-env="http://schemas.xmlsoap.org/soap/envelope/";
return /preFileDoc/inpXML//soap-env:Header/@filename
Finally, the different capitalizations of filename
can be worked around by specifying both:
declare namespace soap-env="http://schemas.xmlsoap.org/soap/envelope/";
return /preFileDoc/inpXML//soap-env:Header/(@filename | @fileName)
Upvotes: 2
Reputation: 20414
You can take the union of multiple attributes. It will be unlikely that this attribute will appear multiple times with different casing, so that should always return a single node:
//soap-env:Header/@filename | //soap-env:Header/@fileName
Optionally, you could wrap it in parentheses, and add [1]
behind it, to always take the first result.
(//soap-env:Header/@filename | //soap-env:Header/@fileName)[1]
If you replace the union with a comma, which creates a sequence instead of a document order node set, you can add a default as well at the end. Maybe not very usefull here, but perhaps in other situations:
(//soap-env:Header/@filename , //soap-env:Header/@fileName, "default.dat")[1]
HTH!
Upvotes: 1
Reputation: 754963
You need to respect and take into account the SOAP XML namespace!
Since I don't know what you're using, I cannot tell you how to do this - but there's the xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"
on the root node, and your @filename
attribute is on the <soap-env:Header .... />
node - so you need to include the XML namespace in your XQuery.
In .NET / C#, you could do it like this (using the "older" XmlDocument
style which supports XPath directly):
// define test XML
string xmlContent =
@"<?xml version='1.0'?>
<preFileDoc xmlns:soap-env='http://schemas.xmlsoap.org/soap/envelope/'>
<senderId>ABC</senderId>
<receiverId>XYZ</receiverId>
<tranxCode>A001</tranxCode>
<inpXML version='1.0' encoding='UTF-8'>
<soap-env:Envelope>
<soap-env:Header msgcode='SPPCONVAKT' orig-system='002FTB' refid='65355ff50a172064484bf9da64c1e245' timestamp='2009-02-11 21:00:10.741' filename='SPPCONVAKT20090128001.dat'/>
<soap-env:Body>
text1
text2
</soap-env:Body>
</soap-env:Envelope>
</inpXML>
</preFileDoc>";
// create XmlDocument and load test data
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlContent);
// define XML namespace manager and add the SOAP namespace to it
XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable);
mgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
// use XPath and the XML namespaces to grab the <Header> node
// the first two nodes <preFileDoc> and <inpXML> are not inside any explicit
// XML namespace
// but the next two (<Envelope> and <Header>) are in the "soap" XML namespace
XmlNode header = doc.SelectSingleNode("/preFileDoc/inpXML/soap:Envelope/soap:Header", mgr);
// read the "filename" attribute from the header node
if(header != null && header.Attributes["filename"] != null)
{
string fileName = header.Attributes["filename"].Value;
}
Upvotes: 0