GetXML from DataTable Specify Option Serialize Column Content Like CData - c#

I have and datable and a column of string data type in that column i put content of type ddl some like
create table
create view
create stored procedure
dt.columns("content") = "create procedure ...etc"
that work ok,
the problem is when i need recovery the content like xml. Now i do that with
Dim xmlcontent = dt.DataSet.GetXml().ToString()
that return a xml like
<NewDataSet>
<Application_table>
<ID>PV</ID>
<NAme>dbo.uvw_Sample</Nombre>
<Content>/*
Run this script on SQL Server 2008 or later. There may be flaws if running on earlier versions of SQL Server.
*/
Create View...
...
</Content>
</Application_table>
</NewDataSet>
the exception is
XML parsing: line 5349, character 59, illegal xml character
i think the content in column content should for example change "<" for "<" or better specifiy the content like cdata
So I want to specify that the serialization of the column be as CDATA. Anyone know if there is way to do it?

You can try converting the nodes in question to a cdata node. This code might be obsolete as its very old, but it still works. I made an xml document from the dataset. Changed all the text nodes to CDATA nodes. Here is the code:
workingds = DataSetWithData
'Convert dataset to xmldatadocument
Dim myxmldoc As Xml.XmlDataDocument = New Xml.XmlDataDocument(workingds)
txtnodes = myxmldoc.GetElementsByTagName(strTextField)
For i = 0 To txtnodes.Count - 1
Me.makecdata(txtnodes(i))
Next i
'this subroutine takes the text node and wraps a cdata tag around it
'and returns it to the document
Public Sub makecdata(ByVal mynode As Xml.XmlNode)
Dim mcnode As Xml.XmlCDataSection, strtemp As String
strtemp = mynode.InnerText
mcnode = (mynode.OwnerDocument.CreateCDataSection(strtemp))
mynode.InnerXml = ""
mynode.AppendChild(mcnode)
mcnode = Nothing
End Sub

Use serialization:
private string DataSetToXml(DataSet ds)
{
using (var ms= new MemoryStream())
{
using (TextWriter sw= new StreamWriter(ms))
{
var xmlSerializer = new XmlSerializer(typeof(DataSet));
xmlSerializer.Serialize(sw, ds);
return Encoding.UTF8.GetString(memoryStream.ToArray());
}
}
}
or you can use .getXml() returned xml se how you can serialize into string Using StringWriter for XML Serialization

Related

Removing empty space from closing XML tag

Below is a code snippet of creating a document:
CdtrAcct = new CdtrAcct
{
Id = new Id
{
IBAN = iban,
Othr = new Othr
{
Id = creditBankAcct
},
},
},
If the IBAN field has a value, then Id is null. However, when the XML file is formed, I get the below:
<CdtrAcct>
<Id>
<IBAN>XXXXXXXXXXXXXXXXXXX</IBAN>
<Othr />
</Id>
</CdtrAcct>
The problem that I have is that the software that reads the XML cannot process the whitespace here: <Othr />. What do I need to do to get <Othr/>?
C# code:
XmlSerializer serializer = new XmlSerializer(typeof(Document));
var textWriter = new StreamWriter(#"C:\BankFiles\Outbox\" + filename + ".xml");
serializer.Serialize(textWriter, config);
textWriter.Close();
Convert the XML to a string (e.g. myString), then you can replace " \>" with "\>" by using
myString.Replace(" \>", "\>");
Afterwards you can print it into a file.
Of course this is a workaround / hack and getting the buggy software fixed should be the first try. However, this should solve your problem immediately.
It's best to avoid processing XML with anything other than a conformant XML parser.
But if you're stuck with it, it's easy enough to put the XML through an identity transformation that re-serializes it without the whitespace.

how can I unbind mixed xml content using c# xml tools rather than regex?

I use "application 1" to create and edit xhtml files.
It has an option to enter annotations into the content of non-empty elements like p, h1, h2, td etc ... which results in mixed xml code sections like this:
<p>Hello <NS1:annotation [...SomeAttributes...]>everybody</NS1:annotation> out there!</p>
For translational purposes I have to export these xhtml files into "application 2" which can't deal with these internal elements. As the annotations are not part of the desired content in the translations removing them before exporting them to application 2 would be a perfect workaround:
<p>Hello everybody out there!</p>
Removing nodes from an XmlDocument reliably finds and removes the internal xml elements but it also deletes the content of the annotation element - loosing the word "everybody" in the example above:
<p>Hello out there!</p>
What I need is rather "unbinding" the content of these internal elemts into the content of the parent element. But so far I haven't found a method using the c# xml tools doing the job.
So far I first save the xhtml file, re-open it as text file and use regedits to remove the annotation. I can even use c# methods for it:
TextFile txt = new TextFile();
string s = txt.ReadFile(filename);
string pattern = #"<NS1:annotation.+>(.+)</NS1:annotation>";
string input = s;
string replacement = "$1";
Regex rgx = new Regex(pattern);
string result = rgx.Replace(input, replacement);
TextFile.Write((filename,result););
This is doubtlessly a better solution as it doesn't loose the content of the annotation but I wonder if there is really not a solution based on the c# Xml-tools that does the job.
Anybody out there who knows it?
I think I found an answer using XmlDocument.
The key is that in mixed xml nodes the text surrounding the node can be adressed as xml nodes too. I wasn't aware of this ...
The following function unbinds the content of the mixed node and releases it into the content of the parent node. I haven't tested it for nodes containing multiple annotations, but that's enough for me at the moment ...
private void removeAnnotations(XmlDocument doc)
{
XmlNamespaceManager manager = new XmlNamespaceManager(new NameTable());
manager.AddNamespace("NS1","http://www.someurl.net");
XmlNodeList annotations = doc.SelectNodes("//NS1:annotation", manager);
int i = 0;
while (i < annotations.Count)
{
//in mixed xml the Siblings are xml text nodes. Therefore we write them into buffers:
string s0 = "";
if(annotations[i].PreviousSibling != null) s0 = annotations[i].PreviousSibling.InnerText;
string s2 = "";
if(annotations[i].NextSibling != null) s2 = annotations[i].NextSibling.InnerText;
//buffer the content of the annotation itself
string s1 = annotations[i].InnerText;
//buffer the link to the parent node before we remove the annotation,
XmlNode parent = annotations[i].ParentNode;
//now remove the annotation
parent.RemoveChild(annotations[i]);
//and apply the new Text to the parent element
parent.InnerText = s0 + s1 + s2;
i++;
}
}

passing xml data into a string to be used as a parameter

Having trouble dealing with xml and to properly use it for my purpose. So i am creating a test method and one of the parameters is xml data and i am not sure how to pass it in.
Service
public IEnumerable<Submissions> CheckingOutForUserReview(string data)
{
var _submissions = DataContextManager.StoredProcs.CheckingOutForUserReview<SSubmissions>(data, s => new Submissions
{
QRCodeGUID = SubmissionsColumnMap.QRCodeGUID(s),
StoragePath = SubmissionsColumnMap.StoragePath(s),
UploadedByUsersID = SubmissionsColumnMap.UploadedByUsersID(s)
});
return _submissions;
}
Stored Proc:
public virtual IEnumerable<T> CheckingOutForUserReview<T>(string data, Func<IDataRecord, T> modelBinder)
{
SqlCommand _command = new SqlCommand("dbo.CheckingOutForUserReview");
_command.CommandType = CommandType.StoredProcedure;
_command.Parameters.Add(new SqlParameter { ParameterName = "Data", SqlDbType = SqlDbType.Xml, Value = data });
return DbInstance.ExecuteAs<T>(_command, modelBinder);
}
This is my TestMethod:
public void CheckingOutForUserReview()
{
string _data = #"<CheckingOutForUserReview xmlns:i=""www.w3.org/2001/XMLSchema-instance"" xmlns=""schemas.name.com/2013/03/Malt.Models"">
<Record>
<QRCodeID>2FAC636E-F96C-4465-9272-760BAF73C0DF</QRCodeID>
<SubmissionID>10B5236C-47FD-468D-B88D-D789CA0C663A</SubmissionID>
<UserID>1</UserID>
<Page>1</Page>
</Record>
</CheckingOutForUserReview>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(_data);
var _Svc = new SubmissionsService();
var _checkins = _Svc.CheckingOutForUserReview(doc.InnerXml);
}
UPDATE:
my CheckingOutForUserReview() method accepts a XmlDocument as i changed it to that in my stored procedure and with what i currently have it is giving an error that i have invalid arguments(System.Xml.XmlDocument) not sure if i messed up somewhere.
If this is a different way i am also open in trying new ways. Thanks for the help.
As I see there are two ways:
You should save your xml into an xml file by adding xml file in your
project then use it with XmlDocument using Load method like:
XmlDocument doc = new XmlDocument.Load(FileName);
...
...
var _checkins = _Svc.CheckingOutForUserReview(doc.innerXml);
Save your xml as a string literal and use it with XmlDocument using
LoadXml method like:
XmlDocument doc = new XmlDocument.LoadXml(stringThatContainsXml);
...
...
var _checkins = _Svc.CheckingOutForUserReview(doc.innerXml);
You can use XDocument and XElement classes as well but my focus on XmlDocument is that it will work for framework less than 3.5 too since XDocument and XElement is introduced in framework 3.5.
Also loading xml into a parser will help to filter out the invalid xml. (if mistakenly tried to use)
Another thing i have noticed in your snippet:
Assert.IsNotNull(_data);
It should come before the initialization of _Svc, because if there is no data in _data initialization doesn't make sense.
So your code looks like:
public void CheckingOutForUserReview()
{
string _data = "I want to pass in xml here";
Assert.IsNotNull(_data); <--------------- See the re-ordering
var _Svc = new SubmissionsService();
var _checkins = _Svc.CheckingOutForUserReview(_data);
}
Like I said in a comment, I think the best way to do this is to save the XML into a separate file.
If you don't want to do that, you can use verbatim string literal (note the double quotes):
string data = #"<CheckingOutForUserReview xmlns:i=""www.w3.org/2001/XMLSchema-instance"" xmlns=""schemas.name.com/2013/03/Malt.Models"">
<Record>
<QRCodeID>2FAC636E-F96C-4465-9272-760BAF73C0DF</QRCodeID>
<SubmissionID>10B5236C-47FD-468D-B88D-D789CA0C663A</SubmissionID>
<UserID>1</UserID>
<Page>1</Page>
</Record>
</CheckingOutForUserReview>";
I don't see what is the problem in passing any kind of strings as a parameter into a method
If your XML is generated from your code, you better have used a StringBuilder to build it to reduce creating new references while concatenating your string.
If your XML is originally from a file, pass the file path into your method, and open the document there. there are a lot of different ways to open and read XML documents, or loading a string to an XML document and deal with it as XML rather than a string.
Examples:
http://www.codeproject.com/Articles/24375/Working-with-XML
http://forum.codecall.net/topic/58239-c-tutorial-reading-and-writing-xml-files/
and finally from MSDN:
http://msdn.microsoft.com/en-us/library/aa288481%28v=vs.71%29.aspx
enjoy

Xml within an Xml

I basically want to know how to insert a XmlDocument inside another XmlDocument.
The first XmlDocument will have the basic header and footer tags.
The second XmlDocument will be the body/data tag which must be inserted into the first XmlDocument.
string tableData = null;
using(StringWriter sw = new StringWriter())
{
rightsTable.WriteXml(sw);
tableData = sw.ToString();
}
XmlDocument xmlTable = new XmlDocument();
xmlTable.LoadXml(tableData);
StringBuilder build = new StringBuilder();
using (XmlWriter writer = XmlWriter.Create(build, new XmlWriterSettings { OmitXmlDeclaration = true }))
{
writer.WriteStartElement("dataheader");
//need to insert the xmlTable here somehow
writer.WriteEndElement();
}
Is there an easier solution to this?
Use importNode feature in your document parser.
You can use this code based on CreateCDataSection method
// Create an XmlCDataSection from your document
var cdata = xmlTable.CreateCDataSection("<test></test>");
XmlElement root = xmlTable.DocumentElement;
// Append the cdata section to your node
root.AppendChild(cdata);
Link : http://msdn.microsoft.com/fr-fr/library/system.xml.xmldocument.createcdatasection.aspx
I am not sure what you are really looking for but this can show how to merge two xml documents (using Linq2xml)
string xml1 =
#"<xml1>
<header>header1</header>
<footer>footer</footer>
</xml1>";
string xml2 =
#"<xml2>
<body>body</body>
<data>footer</data>
</xml2>";
var xdoc1 = XElement.Parse(xml1);
var xdoc2 = XElement.Parse(xml2);
xdoc1.Descendants().First(d => d.Name == "header").AddAfterSelf(xdoc2.Elements());
var newxml = xdoc1.ToString();
OUTPUT
<xml1>
<header>header1</header>
<body>body</body>
<data>footer</data>
<footer>footer</footer>
</xml1>
You will need to write the inner XML files in CDATA sections.
Use writer.WriteCData for such nodes, passing in the inner XML as text.
writer.WriteCData(xmlTable.OuterXml);
Another option (thanks DJQuimby) is to encode the XML to some XML compatible format (say base64) - note that the encoding used must be XML compatible and that some encoding schemes will increase the size of the encoded document (base64 adds ~30%).

Getting a certain node using DataSet

I have the following XML
<xml>
<ObsCont xCampo="field1">
<xTexto>example1</xTexto>
</ObsCont>
<ObsCont xCampo="field2">
<xTexto>example2</xTexto>
</ObsCont>
<ObsCont xCampo="field3">
<xTexto>example3</xTexto>
</ObsCont>
<field>information</field>
</xml>
Is there a way to get the content of "xTexto" inside the ObsCont that has "field2" value for the attribute xCampo using DataSet ?
It would be desireable to have a single liner like the following:
DataSet ds = new DataSet();
ds.ReadXml(StrArquivoProc);
ds.Tables["xml"].Rows[0]["field"].ToString();
//field == "information"
If I use the same method I'm not specifying that I want the one with the desired attribute.
If you have an absolutely known data path then you can use XPath:
Dim myFile = "c:\test.xml"
Dim X As New System.Xml.XmlDocument()
X.Load(myFile)
Dim N = X.SelectSingleNode("//xml/ObsCont[#xCampo=""field2""]/xTexto")
Trace.WriteLine(N.InnerText)
You could certainly use something like Linq to XML to load the entire document into a collection that you could further query or iterate over to use to whatever ends you desire, including binding to data controls. Or you could specifically query the document directly for the desired attribute/element value combination, like below.
XDocument document = XDocument.Parse(xml);
// or document = XDocument.Load(xmlFile)
// System.Xml.Linq namespace
var query = (from obscont in document.Descendants("ObsCont")
where obscont.Attribute("xCampo").Value == "field2"
select obscont.Element("xTexto").Value).First();
Console.WriteLine(query);
Here's the XPathDocument version of Chris Haas' solution, for what it's worth.
Dim myFile = "c:\test.xml"
Dim fs As New FileStream(myFile, FileMode.Open)
Dim doc As New XPathDocument(fs)
fs.Dispose()
Dim nav = doc.CreateNavigator()
Dim node = nav.SelectSingleNode("//xml/ObsCont[#xCampo=""field2""]/xTexto")
Trace.WriteLine(node.Value)
Or if you have the XML in a string, use a StringReader instead.
Dim doc As New XPathDocument(New StringReader(myXml))
'And so forth...'

Categories

Resources