C# CreateDocumentType for non-PUBLIC - c#

I want to get the following output:
<?xml version="1.0" encoding="Windows-1252"?>
<!DOCTYPE SUPRMRT SYSTEM "suprmrt.dtd">
I have the following code:
XmlDocument doc = new XmlDocument();
XmlDocumentType docType = doc.CreateDocumentType("SUPRMRT", "SYSTEM", "suprmrt.dtd", null);
doc.AppendChild(docType);
doc.Save(Console.out);
This produces:
<?xml version="1.0" encoding="Windows-1252"?>
<!DOCTYPE SUPRMRT PUBLIC "SYSTEM" "suprmrt.dtd">
So my question is can I get a result where PUBLIC is replaced by SYSTEM? Also, if I replace "SYSTEM" with null, I get a set of empty quotes. Can I stop that from happening?

Write it like this.
XmlDocumentType docType = doc.CreateDocumentType("SUPRMRT", null, "suprmrt.dtd", null);
Here is the MSDN Documentation
publicId
Type: System.String
The public identifier of the document type or null. You can specify a
public URI and also a system identifier to identify the location of
the external DTD subset.

Related

Unable to get element in XML

<?xml version="1.0" encoding="utf-8"?>
<serv:message
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:serv="http://www.webex.com/schemas/2002/06/service" xsi:schemaLocation="http://www.webex.com/schemas/2002/06/service http://www.webex.com/schemas/2002/06/service.xsd">
<header>
<securityContext>
<webExID/>
<password/>
<siteID/>
<partnerID/>
</securityContext>
</header>
<body>
<bodyContent xsi:type="java:com.webex.service.binding.training.CreateTrainingSession"
xmlns="http://www.webex.com/schemas/2002/06/service/training"
xmlns:com="http://www.webex.com/schemas/2002/06/common"
xmlns:sess="http://www.webex.com/schemas/2002/06/session"
xmlns:serv="http://www.webex.com/schemas/2002/06/service"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.webex.com/schemas/2002/06/service/training http://www.webex.com/schemas/2002/06/service/training/trainingsession.xsd">
<sess:accessControl>
<sess:sessionPassword/>
</sess:accessControl>
<sess:schedule></sess:schedule>
<metaData>
<sess:confName/>
<agenda/>
<description/>
<greeting/>
<location/>
</metaData>
<enableOptions>
<chat/>
<poll/>
<audioVideo/>
<fileShare/>
<applicationShare/>
<desktopShare/>
<annotation/>
<fullScreen/>
<voip/>
</enableOptions>
</bodyContent>
</body>
</serv:message>
Above XML is standard VILT Create Event xml and I need to populate it with proper data.
The issue is I am able to get "securityContent" element using below code and node holds total count of child elements that is 4:
var node = xmlDoc.SelectNodes("/serv:message/header/securityContext/*", GetNameSpace(xmlDoc.NameTable));
But when I try to get another node i.e. "metaData" then I get Count 0 and way to getting element is exactly same except the path to the element.
Below is sample code that I've tried but not working:
static void Main(string[] args)
{
var xmlPathh = #"C:\Users\SKMEENA\Desktop\VILT.xml";// this holds above xml
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(xmlPathh);
var node = xmlDoc.SelectNodes("/serv:message/header/securityContext/*", GetNameSpace(xmlDoc.NameTable));
var member = xmlDoc.SelectNodes("/serv:message/body/bodyContent/metaData/*", GetNameSpace(xmlDoc.NameTable));
}
static XmlNamespaceManager GetNameSpace(XmlNameTable objNameTable)
{
XmlNamespaceManager objNsManager =new XmlNamespaceManager(objNameTable);
objNsManager.AddNamespace("serv", "http://www.webex.com/schemas/2002/06/service");
objNsManager.AddNamespace("ns1", "http://www.webex.com/schemas/2002/06/service/site");
return objNsManager;
}
Anybody has any idea what is wrong with above code and how can I make it working?
The bodyContent node has a default namespace which applies to it and all its children.
You need to add it to the NamespaceManager and then use it in the XPath
var member = xmlDoc.SelectSingleNode("/serv:message/body/body:bodyContent/body:metaData", GetNameSpace(xmlDoc.NameTable));
member.OuterXml.Dump();
static XmlNamespaceManager GetNameSpace(XmlNameTable objNameTable)
{
XmlNamespaceManager objNsManager =new XmlNamespaceManager(objNameTable);
objNsManager.AddNamespace("serv", "http://www.webex.com/schemas/2002/06/service");
objNsManager.AddNamespace("ns1", "http://www.webex.com/schemas/2002/06/service/site");
objNsManager.AddNamespace("body", "http://www.webex.com/schemas/2002/06/service/training");
objNsManager.AddNamespace("sess","http://www.webex.com/schemas/2002/06/session");
return objNsManager;
}
dotnetfiddle

I can't properly select an XML node in a SOAP header in C#.Net

I have an XML document wrapped in a SOAP header but I can't select a single node. I think I am just misunderstanding how to repsresent the tree when nodes are prepended with text. e.g. wsu:Timestamp, wsu:Created
Here is the top part of my XML:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:itk="urn:nhs-itk:ns:201005">
<soap:Header>
<wsa:MessageID>39c6f52b-1be0-42a9-a219-5d6ececd1695</wsa:MessageID>
<wsa:Action>urn:nhs-itk:services:201005:SendCDADocument-v2-0</wsa:Action>
<wsa:To>http://127.0.0.1:4000/syncsoap</wsa:To>
<wsa:From>
<wsa:Address>http://localhost</wsa:Address>
</wsa:From>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="D6CD5232-14CF-11DF-9423-1F9A910D4703">
<wsu:Created>2015-01-30T19:40:00</wsu:Created>
<wsu:Expires>2015-01-30T19:50:00</wsu:Expires>
</wsu:Timestamp>
<wsse:UsernameToken>
<wsse:Username>TKS Server test</wsse:Username>
</wsse:UsernameToken>
</wsse:Security>
</soap:Header>
Here is my code, which throws a null pointer exception on the Select Single Node because it doesn't return a match.
private static XmlDocument CreateSoapEnvelope()
{
XmlDocument soapEnvelop = new XmlDocument();
DateTime myCreatedDate = DateTime.UtcNow;
soapEnvelop.Load(#“c:\myFile.xml");
soapEnvelop.SelectSingleNode("/soap/Envelope/Header/wsse/Security/wsu/Timestamp/Created").InnerText = myCreatedDate.ToString("yyyy-MM-ddTHH:mm:ssZ");
return soapEnvelop;
}
I triple checked for case sensitivity and I don't see a mistake there. And when I put a breakpoint in I can see the XML is loaded into the soapEnvelop object fine.
I implemented the suggestion of using a Namespace Manager and I could select several nodes fine. However, I have an issue with matching the Id value in wsu:Timestamp. I tried the following but all couldn't match:
soapEnvelop.SelectSingleNode("//soap:Envelope/soap:Header/wsse:Security/wsu:Timestamp/Id", ns).InnerText = Guid.NewGuid().ToString();
soapEnvelop.SelectSingleNode("//soap:Envelope/soap:Header/wsse:Security/wsu:Timestamp/wsu:Id", ns).InnerText = Guid.NewGuid().ToString();
soapEnvelop.SelectSingleNode("//soap:Envelope/soap:Header/wsse:Security/wsu:Timestamp", ns).Attributes["Id"].Value = Guid.NewGuid().ToString();
I figured out my last problem. If you have an attribute that is empty then the Value() call must "fail". I had modified my xml doc I was working with when I added in the code suggested below and took out the existing ID and replaced it with "", which is what I was doing with Created and Expires. The issue must be you can have an InnerText for a node that is an empty string but you can't have that for an attribute. Maybe that is considered invalid XML so .Net says "no go dude".
What is odd is that when I changed my code to do this call before my initial setting of Id.
XmlNode myNode = soapEnvelop.SelectSingleNode("//soap:Envelope/soap:Header/wsse:Security/wsu:Timestamp", ns);
myNode.Attributes["wsu:Id"].Value = Guid.NewGuid().ToString();
It set the value fine even if Id was "" in my xml file. That is how I stumbled onto my solution because I left my original call still in the code and it didn't throw an exception so it got me thinking the only difference is Id has a value.
Thanks,
Dan
This is a namespace issue. The nodes that you are selecting don't all belong to the same namespace so effectively does not have access to them. You need to use an XmlNameSpaceManager to store your namespaces and specify which namespace each element belongs to.
Such as:
private static XmlDocument CreateSoapEnvelope()
{
XmlDocument soapEnvelop = new XmlDocument();
DateTime myCreatedDate = DateTime.UtcNow;
soapEnvelop.Load(#"c:\myFile.xml");
XmlNamespaceManager ns = new XmlNamespaceManager(soapEnvelop.NameTable);
ns.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
ns.AddNamespace("wsa", "http://www.w3.org/2005/08/addressing");
ns.AddNamespace("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
ns.AddNamespace("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
soapEnvelop.SelectSingleNode("//soap:Envelope/soap:Header/wsse:Security/wsu:Timestamp/wsu:Created", ns).InnerText = myCreatedDate.ToString("yyyy-MM-ddTHH:mm:ssZ");
}
There are more elegant ways of performing this task but this at least will allow you to proceed.

Exception while reading XML - "Namespace Manager or XsltContext needed"

My xml is as below
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="../../config/janes-deliver.xsl"?>
<!DOCTYPE janes:record SYSTEM "../../config/janesml-delivery-norm-2.1.dtd">
<janes:record xmlns:janes="http://dtd.janes.com/2002/Content/" id="j1891356689831320" pubabbrev="JIQ" sysId="JIQ0105" urname="record">
<janes:metadata xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="j1891356689831320" urname="metadata" xlink:type="simple">
<dc:rights xmlns:dc="http://purl.org/dc/elements/1.1/">Copyright © IHS Global Limited, 2014</dc:rights>
<dc:date xmlns:dc="http://purl.org/dc/elements/1.1/" qualifier="pubDate">30000101</dc:date>
<dc:date xmlns:dc="http://purl.org/dc/elements/1.1/" qualifier="postDate">20140822</dc:date>
<janes:title urname="title">IHS Jane's Navigating the Emerging Markets</janes:title>
<janes:shortTitle urname="shortTitle">Canada</janes:shortTitle>
<janes:sect1 id="j18967561358768718373" urname="sect1">
<janes:para id="j18967561358768718388" urname="para"><janes:link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="jiq0105_a.pdf" qualifier="pdf" urname="link" xlink:type="simple"><janes:linkText urname="linkText">Please click here for the full PDF report.</janes:linkText></janes:link></janes:para>
</janes:sect1>
<janes:sect1 id="j26330201380885096083" updated="y" urname="sect1">
<janes:title urname="title">Military inventories</janes:title>
.......................
I need to retrieve the contents of the tag
I have written a code like below
XmlDocument doc = new XmlDocument();
doc.Load(filepath);
foreach (XmlNode node in doc.SelectNodes("janes:link"))
{
string name = node.Name;
string value = node.InnerText;
// ...
}
I am getting the error "Namespace Manager or XsltContext needed. This query has a prefix, variable, or user-defined function."
Can Some one help ?
Try this:
XmlDocument doc = new XmlDocument();
doc.Load(filepath);
var nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("janes", "http://dtd.janes.com/2002/Content/");
foreach (XmlNode node in doc.SelectNodes(#"//janes:link", nsmgr))
{
//...
}
This answers explains why XmlNamespaceManager is needed.

Parsing URL/web-service

I made a request to a third party API and it gives me the following response in XML.
<?xml version="1.0" ?>
<abc>
<xyz>
<code>-112</code>
<message>No such device</message>
</xyz>
</abc>
I read this using this code.
XmlDocument doc = new XmlDocument();
doc.Load("*** url ***");
XmlNode node = doc.SelectSingleNode("/abc/xyz");
string code = node.SelectSingleNode("code").InnerText;
string msg = node.SelectSingleNode("message").InnerText;
Response.Write("Code: " + code);
Response.Write("Message: "+ msg);
But I get an error on this line:
string code = node.SelectSingleNode("code").InnerText;
Error is:
Object reference not set to an instance of an object.
I changed the first line of your XML file into:
<?xml version="1.0"?>
to make it valid XML. With this change, your code works for me. Without the change, the parser throws an exception.
You can use LINQ to XML (if confortable):
XDocument doc = XDocument.Load(url);
var selectors = (from elements in doc.Elements("abc").Elements("xyz")
select elements).FirstOrDefault();
string code = selectors.Element("code").Value;
string msg = selectors.Element("message").Value;
As you've given it, there doesn't seem to be anything wrong with your code Edit : Your declaration is wrong, as svinja pointed out, and your xml won't even load into the XmlDocument.
However, I'm guessing that your xml is more complicated, and there is at least one namespace involved, which would cause the select to fail.
It isn't pretty, but what you can do is use namespace agnostic xpath to locate your nodes to avoid using a XmlNamespaceManager:
XmlDocument doc = new XmlDocument();
doc.Load("*** url ***");
XmlNode node = doc.SelectSingleNode("/*[local-name()='abc']/*[local-name()='xyz']");
string code = node.SelectSingleNode("*[local-name()='code']").InnerText;
string msg = node.SelectSingleNode("*[local-name()='message']").InnerText;
Response.Write("Code: " + code);
Response.Write("Message: "+ msg);
Edit - Elaboration
Your code works fine if you correct the declaration to <?xml version="1.0"?>
However, if you introduce namespaces into the mix, your code will fail unless you use namespace managers appropriately.
My agnostic xpath above will also parse an xml document like so:
<?xml version="1.0"?>
<abc xmlns="foo">
<xyz xmlns="bar">
<code xmlns="bas">-112</code>
<message xmlns="xyz">No such device</message>
</xyz>
</abc>
<?xml version="1.0">
<abc>
<xyz>
<code>-112</code>
<message> No such device </message>
</xyz>
</abc>
try to set a list:
XmlNodeList nodeList = root.SelectNodes("/abc/xyz");
then read all the nodes and get their text:
foreach(XmlNode node in nodeList)
{
if(node.Name == "code")
{
string code = node.InnerText;
}
else
if(node.Name == "message")
{
string msg = node.InnerText;
}
}
[XmlRoot("abc")]
public class Entity
{
[XmlElement("xyz")]
public SubEntity SubEntity { get; set; }
}
public class SubEntity
{
[XmlElement("code")]
public string Code { get; set; }
[XmlElement("message")]
public string Message { get; set; }
}
And use standart xmlserializer
var xmlSerializer = new XmlSerializer(typeof(Entity));
var result = xmlSerializer.Deserialize(new XmlTextReader("*** url ***"));
Response.Write("Code: " + result.SubEntity.Code);
Response.Write("Message: "+ result.SubEntity.Message);

C# XmlNodeReader exception NodeType not supported

I'm getting the exception that NodeType "None" is not supported when trying to run the following code.
public int ObjectContentI(string XmlPath)
{
XmlNodeReader xnr = new XmlNodeReader(this.xmlr.SelectSingleNode(XmlPath));
return xnr.ReadElementContentAsInt();
}
this.xmlr is a XmlDocument with a document successfully loaded in it. XmlPath contains a valid XPath url.
How do i set the NodeType (xnr.NodeType is readonly) or am I doing something else wrong?
Part of my XML:
<?xml version="1.0" encoding="utf-8" ?>
<ship weapons="0">
<cost>
<metal>250</metal>
<crystal>100</crystal>
</cost>
<health>
<shields>750</shields>
<sregene>10</sregene>
<hitpoints>1000</hitpoints>
<oxygen cps="2">25000</oxygen>
</health>
My XPath: "/ship/health/shields/text()"
Well, your approach is correct but not completely.
Let's suppose
XmlNode n = myXMLDoc.SelectSingleNode("/ship/health/shields/");
n.InnerXML OR n.InnerText should give you what you need.
Though conqenator provided you with code that fixed your problem following is reasoning why it didn't work in the first place:
If you don't call the Read method on a XmlNodeReader or any of the classes that derive from XmlReader, you will always get a XmlNodeType.None NodeType, which is the reason for the error. To fix the code you provided and to get an int back this is what the code needs to look like:
public int ObjectContentI(string XmlPath)
{
int result;
using(XmlNodeReader xnr = new XmlNodeReader(this.xmlr.SelectSingleNode(XmlPath))){
while(xnr.Read()){
result = xnr.ReadElementContentAsInt();
}
}
return result;
}
Note that the XPath to get this wroking needs to change to /ship/health/shields since ReadElementContentAsInt() returns the content of the element and won't work on a Text Node, which what you get when using /ship/health/shields/text().
Notice that I have also wrapped the XmlNodeReader in a using block, which will dispose of the XmlNodeReader once you are done with it to free up resources.

Categories