I am having some difficulty with an xPath expression.
Context: I am using an XML document to store queries / stored procedure names in an ASP application. I use a utility function to load the xmldocument (if it isn't previously loaded) and I am attempting to select the node set from the document that matches an Id element. Here is my Xml document:
<Queries>
<Id>USER001
<Sql>spUsers_GetUserByUserName</Sql>
</Id >
<Id <USER002
<Sql>spUsers_GetUserByEmail</Sql>
</Queries>
Here is the code (I am using VB.NET)
Module Utility
private sqlXml as xmldocument
'....other stuff.....
Public Function GetSql(queryId as string) as string
dim qry as string
dim node as XmlNode
if sqlXml is nothing then
sqlXml = new xmldocument
sqlXml.Load (..path)
end if
qry = "//Id['" & queryId & "']" 'xPath to select the Id node = to paramter passed
node = sqlxml.SelectSingleNode(qry) 'set node <Id><Sql></Sql></Id>
return node.SelectSingleNode("//Sql").InnerText 'Return the Sql element value from the Id
End Function
The Problem:
the node variable only returns the first element. I have verified the that the qry string that is used to SelectSingleNode IS the correct Id value (i.e. USER002) - however the node is getting loaded with the USER001 element. It is obviously the xPath expression that is messed up. What do I need to tweak on the xPath expression so that I can return the correct <Id> element and corresponding child <Sql> element.
Any help would be appreciated.
Google XML COOKTOP and install it. It's a great little freeware app for trying out XPATH and XSLT expressions on XML data files and seeing the results.
It looks like you're trying to to construct an expression like //Id['USER002']. That will select all the E elements for which the effective boolean value of 'USER002' is true - which is all of them. It's not clear what you intended because your XML sample is a mess, but it should be something like //Id[#id='USER002']
Also, you really shouldn't be constructing XPath expressions by string concatenation. It leaves you prone to injection attacks and to accidental misfunctioning when someone supplies a string containing quotes. It's also inefficient. Construct a string containing a variable reference $param, and set the parameter from the API. (Don't know how to do that in VB, I'm afraid).
Related
There is a tag which is of type 2 ("required, empty if unknown"), with value representation Integer String which I would like to leave empty. I have tried creating the attribute like so:
var attribute = new DicomIntegerString(DicomTag.SeriesNumber, string.Empty);
The storing of the file works. When I read the file again, the result of the following call returns null:
var result = dicomDataset.GetString(DicomTag.SeriesNumber); // <-- this is null
How can I set the element to be correctly "zero-length", or "empty, if unknown"?
Thanks.
As already mentioned in the comments, the code to set an empty string in the dataset is correct:
dataset.AddOrUpdate(new DicomIntegerString(DicomTag.SeriesNumber, string.Empty));
Note that you could also write a null value:
dataset.AddOrUpdate(new DicomIntegerString(DicomTag.SeriesNumber, (string)null));
Writing out the dataset will create an empty tag for SeriesNumber in exactly the same way in both cases, as both cases are equivalent in DICOM.
The code to read the tag back is also correct, and the fact that it returns null is due to this equivalence, which creates an ambiguity in the interpretation of an empty string tag in DICOM. As the number of values in a DICOM string tag is defined only by the string itself (and the number of backslashes it contains), there is no difference between a tag with no values (which usually is represented by a null value), and a tag with an empty string (which would be represented by a "" value). For consistence with other tags it makes sense to return null for a tag with VM 0 - for non-string VRs there is no ambiguity here, as the length of a value is defined. For string values it could also make sense to return an empty string instead - both approaches have pros and cons, so in the end it is a design decision of the library creators.
In fo-dicom, it is probably best to handle both cases (e.g. using something like string.IsNullOrEmpty). If you read the value from a file dataset, you always get null, but if you are writing an empty string to a tag in a dataset (first version shown above) and read it back, you will get the same empty string back.
As an aside: in pydicom (the common Python DICOM library) there was a discussion about this same design decision, and in the end a configuration entry was added that defines the behavior (e.g. return None or an empty string for such values).
i'm trying to get the node value in an XML Response. I'm very new to ASP.
Here is the XML:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"/>
<soap:Body>
<ns2:getTextoTsjResponse xmlns:ns2="http://x.com/x/act" xmlns:ns3="http://i.e.com" xmlns:ns4="http://comun.e.com">
<return>
<ns3:texto>
<ns3:datos>
<xop:Include href="cid:888a-4ad6-a511-9c6f0490590e-398#entidad.com" xmlns:xop="http://www.w3.org/2004/08/xop/include"/>
</ns3:datos>
<ns3:extension>pdf</ns3:extension>
</ns3:texto>
<ns3:textoAnonimizado>
<ns3:datos>
<xop:Include href="cid:888a-4ad6-a511-9c6f0490590e-399#entidad.com" xmlns:xop="http://www.w3.org/2004/08/xop/include"/>
</ns3:datos>
<ns3:extension>pdf</ns3:extension>
</ns3:textoAnonimizado>
</return>
</ns2:getTextoTsjResponse>
</soap:Body>
</soap:Envelope>
I succeded geting the XMLDoc and parse. What im trying to do then is get href values within node.
Here is the ASP code.
'Response from server with the XML
xmlParseado = response.Text
Set xmlDoc = Server.CreateObject("MSXML2.DOMDocument")
xmlDoc.loadXML(xmlParseado)
if xmlDoc.parseError.errorcode <> 0 then
Response.Write("XML Error...<br>")
else
Call xmlDoc.setProperty("SelectionLanguage", "XPath")
Call xmlDoc.setProperty("SelectionNamespaces", "xmlns:ns3")
Dim node
'Here im trying to get href value from <ns3:datos> node.
Set node = xmlDoc.selectSingleNode("//ns3:texto//ns3:datos//*")
If (node Is Nothing) Then
Response.write "nothing"
Else
response.write(TypeName(node) & "<br />")
End If
end if
Some help would be apreciated.
Thanks in advance
You are really close.
Sadly your XML (like many poorly designed XML documents) suffers from namespace overkill. If you think of elements like data files on a file system, these XML designers are paranoid that two files (elements) will have the same name, so they put every file (element) on a separate disk instead of just using folders (nesting elements) for context. In my entire career, I've never run into an issue with two files having the same name, but every day, there's a post on Stackoverflow from someone having trouble with namespaces.
So think of namespaces like a separate disk in a filesystem. The document specifies each "disk" with a nick name (the prefix like ns3), and a location (the URI like http://i.e.com). Now when you're querying XML with XPath, have to tell the parser about all of the namespaces (disks), and you specify the prefix in front of every element on the "disk". You're XPath will look like "//ns3:datos", not just "//datos".
So armed with namespaces, they became the "solution" for everything. When SOAP was created, the designers went crazy with namespaces, and as a result, everyone put namespaces in everything. The designers of SOAP must have been worried that their Header, Envelope and Body element names would be re-used in SOAP message data. Instead of naming the elements "SOAP_Header", "SOAP_Envelope", and "SOAP_Body" that everyone could remember, they implemented SOAP with XML namespaces just in case the message content accidentally also included an element named "Header", "Envelope" or "Body".
When you set the SelectionNamesSpaces, you need to set both the prefix and the URI. In this example I have all the namespaces in your document.
Good luck with your project, and please join me in killing namespaces where ever possible :)
if xmlDoc.parseError.errorcode <> 0 then
Response.Write("XML Error...<br>")
' NOTE: Avoid nesting else statements, just stop.
Response.End
End If
Call xmlDoc.setProperty("SelectionLanguage", "XPath")
' NOTE: you're missing the URI here in your namespace http://i.e.com
' Call xmlDoc.setProperty("SelectionNamespaces", "xmlns:ns3")
' Add all of the namespaces, including the prefix and URI
Call xmlDoc.setProperty("SelectionNamespaces", "xmlns:xop='http://www.w3.org/2004/08/xop/include' xmlns:ns2='http://x.com/x/act' xmlns:ns3='http://i.e.com' xmlns:ns4='http://comun.e.com'")
'Here im trying to get href value from <ns3:datos> node.
Dim node
Set node = xmlDoc.selectSingleNode("//ns3:texto//ns3:datos//xop:Include")
If (node Is Nothing) Then
Response.write "nothing"
Else
Response.write( node.getAttribute( "href" ) )
End If
' Here's how to get all of the Includes
Dim ndList
set ndList = xmlDoc.selectNodes( "//xop:Include" )
for each ndInclude in ndList
Response.write( ndInclude.getAttribute( "href" ) )
next
I want to load XML in a single table of a dataset. I use following code
string val = getAbonentInfoParametr(ai,"abonentDescription");
DataSet ds = new DataSet();
ds.ReadXml(new StringReader(val));
but when I do this, I got three tables because in one node of XML file I now get HTML code that I want to have like a string field in my only table. What should I do?
Also I prefer not to use scheme files because the structure of that xml file can be changeable except several field that I use, please suggest me something.
Use CDATA to wrap around the HTML, otherwise there is no way to differentiate HTML from XML.
I want to add an attribute to the dataset declared below whose value is the value of one of the field in the row.
So I want to add the id as shown below.
<root>
<Table id="GAS-405">
<apple>2009FA</apple>
<orange>3.00</orange>
<pear>BGPR</pear>
<banana>GAS-405</banana>
</Table>
</root>
This will help me identify the node later in my application.
Is this possible? Is this easier to do using XMLDocument?
Dim sdaFoo As SqlDataAdapter = New SqlDataAdapter("SELECT BLAH FROM BLAHBLAH", conn)
Dim dsFoo As DataSet = New DataSet()
dsFoo.DataSetName = "apple"
sdaFoo.Fill(dsFoo)
dsFoo.WriteXml("C:\Inetpub\wwwroot\foo.xml")
Dataset.WriteXml() is really a convenience method rather than a flexible way of dealing with XML.
You'll need to take another approach. There are a few options:
If you're just adding a single attribute, you could hack it into the resulting xml by re-opening the file as an XDocument, adding the attribute to the necessary element, and saving it again. Not too elegant, but easy, and sometimes easy is best. Even better, just use WriteXml() to put your xml into a string, then load the string as your XDocument.
Generate the XML from your query directly, rather than as a dataset. Sql Server 2005 and 2008 have some good XML methods that allow you to select a set of rows as XML (SELECT ... FOR XML) and specify what it looks like.
Use XmlSerialization for your dataset and inject the attribute using custom control of the serialization process.... which will be way more trouble than it's worth.
Store the attribute somewhere else outside of your XML and use some kind of object to keep track of it. Not really sure what your code is like, but that might be a great option.
Use GetXML() method of DataSet to get whole XML as a string. Then add your custom attributes and write that string into xml file using StreamWriter.
I want to read an specific xml node and its value for example
<customers>
<name>John</name>
<lastname>fetcher</lastname>
</customer>
and my code behind should be some thing like this (I don't know how it should be though):
Response.Write(xml.Node["name"].Value)
As I said it is just an example because I don't know how to do it.
The most basic answer:
Assuming "xml" is an XMLDocument, XMLNodeList, XMLNode, etc...
Response.Write(xml.SelectSingleNode("//name").innerText)
Which version of .NET are you using? If you're using .NET 3.5 and can use LINQ to XML, it's as simple as:
document.Descendant("name").Value
(except with some error handling!) If you're stuk with the DOM API, you might want:
document.SelectSingleNode("//name").InnerText
Note that this hasn't shown anything about how you'd read the XML in the first place - if you need help with that bit, please give more detail in the question.
If using earlier versions of the .Net framework, take a look at the XMLDocument class first as this is what you'd load the XML string into. Subclasses like XMLElement and XMLNode are also useful for doing some of this work.
haven't tried testing it but should point you in the right direction anyway
'Create the XML Document
Dim l_xmld As XmlDocument
'Create the XML Node
Dim l_node As XmlNode
l_xmld = New XmlDocument
'Load the Xml file
l_xmld.LoadXml("XML Filename as String")
'get the attributes
l_node = l_xmld.SelectSingleNode("/customers/name")
Response.Write(l_node.InnerText)