DTD must be defined before the document root element - c#

I'm creating an XML file programatically. To create the starting tag I have the code:
Dim XDoc As XDocument = <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Customers></Customers>
It's then followed by looping through the data, adding in the required elements using the Root.Add method. The XML displays in the browser successfully.
Xdoc.Root.Add(<customer>
<fields>
</customer>
When some clients connect to this XML data, if there is no data to retrieve the page is displayed as:
<?xml version="1.0"?>
<Customers/>
When reading the XML URL from a .NET project:
Dim Xdoc As XDocument = XDocument.Load(UrlToXmlFile)
The error "DTD must be defined before the document root element" is thrown.
Although I can trap the error, I thought perhaps I may have done something wrong when creating the XML (XML isn't my strong point).
Some sites suggest adding a DTD (<!DOCTYPE note SYSTEM "Note.dtd"> for example). I don't know if this is correct or if I can ignore the error or if there is a better way to to declare this?
Update: when i view the page directly in Chrome, it displays the XML as
<Customers>
<customer>....</customer>
<customer>....</customer>
</Customers>
in IE it displays as
<?xml version="1.0"?>
<Customers>
<customer>....</customer>
<customer>....</customer>
</Customers>
but in both browsers when i look at 'view source' it shows
<Customers>
<customer>....</customer>
<customer>....</customer>
</Customers>
I don't know of this would be an issue?
Update 2
XDoc.Save(Sr)
Response.Clear()
Response.Buffer = True
Response.Charset = ""
Response.Cache.SetCacheability(HttpCacheability.NoCache)
Response.ContentType = "application/xml"
Response.Write(Sr.GetStringBuilder.ToString)
Response.Flush()
Response.End()

Here is an example showing the generation/saving and loading of your xml with no errors.
Dim XmlFile As String = "C:\\Temp\\TestData.xml"
Dim XDoc As XDocument = <?xml version="1.0" encoding="UTF-8"?><Customers></Customers>
For ForCount As Integer = 0 To 10
XDoc.Root.Add("<customer>Customer" & ForCount.ToString & "</customer>")
Next
XDoc.Save(XmlFile)
Dim XDocReader As XDocument = XDocument.Load(XmlFile)
Also it sounds like you might be using a web service. Use fiddler to verify your web service is not adding in that attribute when serving the data. I do not see how you are exporting the XML. Make sure you are not just doing a .ToSrting on XDoc, that will only generate the inner XML.

Related

XmlDocument, preformatted xml: Add new line after XML declaration only

I need to add a line after xml declaration to process a file on an external system that rejects it if missing.
I had formatted the doc by myself on creation and signing it, so I don't want to mess with formatting as corrupts the signature (it has also third-party external signed documents)
.
Yes, I can open it as text, use replace "?><" by "?>\r\n<", save it, or do everything manually, but I want to do it "the XmlDocument" way.
What I have:
<?xml version="1.0" encoding="ISO-8859-1"?><LceEnvioOblig xmlns="http://www.sii.cl/SiiLce" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sii.cl/SiiLce LceEnvioOblig_v10.xsd" version="1.0">
<DocumentoEnvioOblig ID="EnvioOblig_12868626-6_76876251-1">
<Caratula>
<RutEnvia>12868626-6</RutEnvia>
<RutContribuyente>76876251-1</RutContribuyente>
<TmstFirmaEnv>2019-01-15T12:00:14-03:00</TmstFirmaEnv>
</Caratula>
What I need:
<?xml version="1.0" encoding="ISO-8859-1"?>
<LceEnvioOblig xmlns="http://www.sii.cl/SiiLce" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sii.cl/SiiLce LceEnvioOblig_v10.xsd" version="1.0">
<DocumentoEnvioOblig ID="EnvioOblig_12868626-6_76876251-1">
<Caratula>
<RutEnvia>12868626-6</RutEnvia>
<RutContribuyente>76876251-1</RutContribuyente>
<TmstFirmaEnv>2019-01-15T12:00:14-03:00</TmstFirmaEnv>
</Caratula>
Relevant code:
signedXml.ComputeSignature();
XmlElement xmlDigitalSignature = signedXml.GetXml();
xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
var dec = xmlDoc.CreateXmlDeclaration("1.0", Constantes.SaveEncoding.EncodingName,"no");
using (var sw = new StreamWriter(salida, false, Constantes.SaveEncoding))
{
xmlDoc.Save(sw);
}
Note I am not using indentations and PreserveWhitespace has not worked fine for me.
Any suggestions or best way to do it?

How to add data after xml in c# and read the xml after?

I've got to create a file with xml header and after that i have to put normal data, smthing like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Header>
<Algorithm>alg</Algorithm>
<nod2>aaa</nod2>
<nod3>bbb</nod3>
<node>
<User>
<Email />
<SessionKey />
</User>
</node>
</Header>
Data of the file....
I've already got the code to write it to the file.
Code for that part:
private void setHeader(FileStream output, string nod2, string nod3, string )
{
XmlDocument doc = new XmlDocument();
XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", "yes");
doc.AppendChild(docNode);
XmlNode header = doc.CreateElement("Header");
doc.AppendChild(header);
XmlNode algorithm = doc.CreateElement("Algorithm");
algorithm.InnerText = "alg";
header.AppendChild(algorithm);
XmlNode node2= doc.CreateElement("nod2");
node2.InnerText = nod2;
header.AppendChild(node2);
XmlNode node3= doc.CreateElement("nod3");
node3.InnerText = nod3;
header.AppendChild(node3);
XmlNode node= doc.CreateElement("node");
header.AppendChild(node);
XmlNode user1 = doc.CreateElement("User");
node.AppendChild(user1);
XmlNode mail = doc.CreateElement("Email");
user1.AppendChild(mail);
XmlNode sessionKey = doc.CreateElement("SessionKey");
user1.AppendChild(sessionKey);
doc.Save(output);
}
It work's pretty well, but when i want to read it with
private void readHeader(FileStream input, out string algorithm)
{
XmlDocument doc = new XmlDocument();
doc.Load(input);
}
I got an error that when the "Data of the file..." starts: "Data on the root level is invalid".
Is there a way to do it with the data after whole xml, or have i to add the data as a node?
This can be done in multiple ways. In comments, you've indicated that the best way is unacceptable for reasons outside the scope of the discussion. For completeness, I'm going to put that one first anyway. Skip down to tl;dr for what I think you'll have to end up doing.
The preferred way to do this is to base64 encode the encrypted data and put it in a CDATA block:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<File>
<Header>
<Algorithm>alg</Algorithm>
<nod2>aaa</nod2>
<nod3>bbb</nod3>
<node>
<User>
<Email />
<SessionKey />
</User>
</node>
</Header>
<Data><![CDATA[
ICAgIFhtbE5vZGUgYWxnb3JpdGhtID0gZG9jLkNyZWF0ZUVsZW1lbnQoIkFsZ29yaXRobSIpOw0K
ICAgIGFsZ29yaXRobS5Jbm5lclRleHQgPSAiYWxnIjsNCiAgICBoZWFkZXIuQXBwZW5kQ2hpbGQo
YWxnb3JpdGhtKTsNCiAgICBYbWxOb2RlIG5vZGUyPSBkb2MuQ3JlYXRlRWxlbWVudCgibm9kMiIp
Ow0KICAgIG5vZGUyLklubmVyVGV4dCA9IG5vZDI7DQogICAgaGVhZGVyLkFwcGVuZENoaWxkKG5v
ZGUyKTsNCiAgICBYbWxOb2RlIG5vZGUzPSBkb2MuQ3JlYXRlRWxlbWVudCgibm9kMyIpOw0KICAg
IG5vZGUzLklubmVyVGV4dCA9IG5vZDM7DQogICAgaGVhZGVyLkFwcGVuZENoaWxkKG5vZGUzKTs=
]]></Data>
</File>
That's the canonical answer to this question.
But you've told me that in your case, a requirement has been imposed that you can't do it that way.
Second choice is MIME (actually, MIME might be the first choice and the above might be the second). But I have a feeling they won't like MIME either.
Third choice, read the file as a string and search for some marker that's inserted between the XML and the binary data, something like a MIME boundary.
tl;dr
If they won't let you add such a marker to the file (and I bet they won't), search for the first occurrence of the substring "</Header>":
var xml = File.ReadAllText(filePath);
var endTag = "</Header>";
var headerXML = xml.Substring(0, xml.IndexOf(endTag) + endTag.Length);
var xdHeader = new XmlDocument();
xdHeader.LoadXml(headerXML);
I tested your code with writing directly to a file, doc.Save(#"c:\temp\test1.xml");
And loading from that file works fine. So there is nothing wrong with your xml document. Check your FileStream. Do you flush and close it properly? Does it have UTF-8 encoding?
What's the input in the node strings. Nothing that is invalid according to xml rules?
After a single root node, only comments and processor instructions can be written to xml. So, you can try to write your data in the comments.
It will look like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Header>
...
</Header>
<!-- your data -->
<!-- another data -->
This method has limitations: your data may not contain -- (double-hyphen) and may not end in -.
But it is better, of course, not to do so.

Append XMLDocument to other

I have following two xml strings
<?xml version="1.0"?>
<AccessRequest xml:lang='en-US'>
<AccessLicenseNumber>YOURACCESSLICENSENUMBER</AccessLicenseNumber>
<UserId>YOURUSERID</UserId>
<Password>YOURPASSWORD</Password>
</AccessRequest>
and
<?xml version="1.0" ?>
<RatingServiceSelectionRequest>
<PickupType>
<Code>01</Code>
</PickupType>
<Shipment>
<Description>Rate </Description>
<Shipper>
<Address>
<PostalCode>originzip</PostalCode>
</Address>
</Shipper>
<ShipTo>
<Address>
<PostalCode>destinationzip</PostalCode>
<CountryCode>countrycode</CountryCode>
</Address>
</ShipTo>
<Service>
<Code>11</Code>
</Service>
<Package>
<PackagingType>
<Code>02</Code>
<Description>Package</Description>
</PackagingType>
<Description>Rate Shopping</Description>
<PackageWeight>
<Weight>weight</Weight>
</PackageWeight>
</Package>
<ShipmentServiceOptions/>
</Shipment>
</RatingServiceSelectionRequest>
I want to append second xml string to first one. I tried writing both XmlDocuments to a XmlWriter. But it throws exception "Cannot write XML declaration. XML declaration can be only at the beginning of the document."
Stream stm = req.GetRequestStream();
XmlDocument doc1 = new XmlDocument();
XmlDocument doc2 = new XmlDocument();
doc1.LoadXml(xmlData1);
doc2.LoadXml(xmlData2);
XmlWriterSettings xws = new XmlWriterSettings();
xws.ConformanceLevel = ConformanceLevel.Fragment;
using (XmlWriter xw = XmlWriter.Create(stm, xws))
{
doc1.WriteTo(xw);
doc2.WriteTo(xw);
}
How can I append it as is? Please help
Remove <?xml version="1.0" ?> from second xml string before appending it to first xml string.
I had this problem in the past. The two lines of code below did the job:
var MyDoc = XDocument.Load("File1.xml");
MyDoc.Root.Add(XDocument.Load("File2.xml").Root.Elements());
If you already have strings ready, then please use the Parse function instead of Load.
Please notice I am using the System.Xml.Linq that uses XDocument instead of XmlDocument class.
EDIT
As I understood, you need both documents to be concatenated as is. The problem is that it will eventually leads to an invalid XML document for two reasons :
the document will contain two root nodes: AccessRequest and RatingServiceSelectionRequest. A valid XML document contains only one root node.
There must be only one <?xml version="1.0" ?> XML declaration at the beginning of a document.
If the UPS api your are using is fed with an invalid XML, you unfortunately can not use XML objects. Therefore you will have to use a simple string concatenation to achieve what you want:
var xml = xmlData1 + xmlData2;

Display deserialized XML on ASP.NET page

How can I display XML output on ASP.NET page with XML tags?
XmlDocument doc = (XmlDocument)JsonConvert.DeserializeXmlNode(jsonOutput, "root");
Console.WriteLine(doc.OuterXml);
I would like to get results on my page like this:
<root>
<id>108013515952807</id>
<posts>
<data>
<message>This...Game... http://www.youtube.com/watch?v=l8Xsex0pqXY</message>
<id>108013515952807_470604423027046</id>
<created_time>2013-05-15T20:02:31+0000</created_time>
</data>
<data>
<message>Streaming in a few minutes! http://www.youtube.com/watch?v=IYnHDT6V82k</message>
<id>108013515952807_470538076367014</id>
<created_time>2013-05-15T16:46:36+0000</created_time>
</data>
</posts>
</root>
I tried this but I get no XML tags like in example above.
Response.Write("<BR>" + doc.OuterXml);
If you just put XML onto a webpage, the browser thinks it might be HTML and "renders" it, which is why you can't see the tags. You need to encode the XML
You can use the method
Response.Write(Server.HtmlEncode(doc.OuterXml));
Try
XElement.Parse(request.OuterXml).ToString()
If you want prettified XML string,
refer to: What is the simplest way to get indented XML with line breaks from XmlDocument?

Reading contents of XML file without having to remove the XML declaration

I want to read all XML contents from a file. The code below only works when the XML declaration (<?xml version="1.0" encoding="UTF-8"?>) is removed. What is the best way to read the file without removing the XML declaration?
XmlTextReader reader = new XmlTextReader(#"c:\my path\a.xml");
reader.Read();
string rs = reader.ReadOuterXml();
Without removing the XML declaration, reader.ReadOuterXml() returns an empty string.
<?xml version="1.0" encoding="UTF-8"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">http://www.as.com/ver/ver.IClaimver/Car</a:Action>
<a:MessageID>urn:uuid:b22149b6-2e70-46aa-8b01-c2841c70c1c7</a:MessageID>
<ActivityId CorrelationId="16b385f3-34bd-45ff-ad13-8652baeaeb8a" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">04eb5b59-cd42-47c6-a946-d840a6cde42b</ActivityId>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">http://localhost/ver.Web/ver2011.svc</a:To>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Car xmlns="http://www.as.com/ver">
<carApplication>
<HB_Base xsi:type="HB" xmlns="urn:core">
<Header>
<Advisor>
<AdvisorLocalAuthorityCode>11</AdvisorLocalAuthorityCode>
<AdvisorType>1</AdvisorType>
</Advisor>
</Header>
<General>
<ApplyForHB>yes</ApplyForHB>
<ApplyForCTB>yes</ApplyForCTB>
<ApplyForFSL>yes</ApplyForFSL>
<ConsentSupplied>no</ConsentSupplied>
<SupportingDocumentsSupplied>no</SupportingDocumentsSupplied>
</General>
</HB_Base>
</carApplication>
</Car>
</s:Body>
</s:Envelope>
Update
I know other methods that use NON-xml reader (e.g. by using File.ReadAllText()). But I need to know a way that uses an xml method.
There can be no text or whitespace before the <?xml ?> encoding declaration other than a BOM, and no text between the declaration and the root element other than line break.
Anything else is an invalid document.
UPDATE:
I think your expectation of XmlTextReader.read() is incorrect.
Each call to XmlTextReader.Read() steps through the next "token" in the XML document, one token at a time. "Token" means XML elements, whitespace, text, and XML encoding declaration.
Your call to reader.ReadOuterXML() is returning an empty string because the first token in your XML file is an XML declaration, and an XML declaration does not have an OuterXML.
Consider this code:
XmlTextReader reader = new XmlTextReader("test.xml");
reader.Read();
Console.WriteLine(reader.NodeType); // XMLDeclaration
reader.Read();
Console.WriteLine(reader.NodeType); // Whitespace
reader.Read();
Console.WriteLine(reader.NodeType); // Element
string rs = reader.ReadOuterXml();
The code above produces this output:
XmlDeclaration
Whitespace
Element
The first "token" is the XML declaration.
The second "token" encountered is the line break after the XML declaration.
The third "token" encountered is the <s:Envelope> element. From here a call to reader.ReadOuterXML() will return what I think you're expecting to see - the text of <s:Envelope> element, which is the entire soap packet.
If what you really want is to load the XML file into memory as objects, just call
var doc = XDocument.Load("test.xml")
and be done with the parsing in one fell swoop.
Unless you're working with an XML doc that is so monstrously huge that it won't fit in system memory, there's really not a lot of reason to go poking through the XML document one token at a time.
What about
XmlDocument doc=new XmlDocument;
doc.Load(#"c:\my path\a.xml");
//Now we have the XML document - convert it to a String
//There are many ways to do this, one should be:
StringWriter sw=new StringWriter();
doc.Save(sw);
String finalresult=sw.ToString();
EDIT: I'm assuming you mean you actually have text between the document declaration and the root element. If that's not the case, please clarify.
Without removing the extra text, it's simply an invalid XML file. I wouldn't expect it to work. You don't have an XML file - you have something a bit like an XML file, but with extraneous stuff before the root element.
IMHO you can't read this file. It's because there's a plain text before the root element <s:Envelope> which makes whole document invalid.
You're parsing an XML document as XML just to obtain the source text? Why?
If you really want to do that then:
string rs;
using(var rdr = new StreamReader(#"c:\my path\a.xml"))
rs = rdr.ReadToEnd();
Will work, but I'm really not sure that is what you actually want. This pretty much ignores that it's XML and just reads the text. Useful for some things, but not a lot.

Categories

Resources