My program takes user input and uses it to create a query. The results of that query will then be put into an XML file with XElements based on their selections. I have a string staff which i set equal to the value of staffType.
Where staff is declared w/ snippet of query code:
using (
var conn = new SqlConnection("Server=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;Database=KUDERDEV;User ID=xxxxxxxxxxxxxxxxxx;Password= xxxxxxxx;Trusted_Connection=False;Encrypt=True;Connection Timeout=30;")
)
{
conn.Open();
bool quit = false;
string choice;
string staff;
SqlCommand cmd = new SqlCommand();
while (!quit)
{
Console.WriteLine("Sort by staffType: K12Staff, psStaff, WFStaff or none?");
string staffType = Console.ReadLine();
staff = staffType;
if (staffType == "K12Staff")
{
Console.WriteLine("Sort by code, date, both, or none?");
choice = Console.ReadLine();
switch (choice)
{
case "code":
Console.WriteLine("Sort by code1 or code2?");
string codeCol = Console.ReadLine();
Console.WriteLine("Enter desired code");
string code = Console.ReadLine();
cmd = new SqlCommand("SELECT * FROM Staff WHERE (Staff." + #codeCol + "='" + #code + "') AND staffType ='" + #staffType + "' FOR XML PATH('staff'), ROOT('k12Staff')", conn);
quit = true;
staff = staffType;
break;
When the query string is complete, I go into another using statement without closing the first one to write the XML file. Here I want to change the format of the XML (XElement) depending on which staffType was chosen.
Writing the XML file snippet:
using (cmd)
{
using (var reader = cmd.ExecuteXmlReader())
{
var doc = XDocument.Load(reader);
string path = #"Staff." + DateTime.Now.ToString("yyyyMMdd") + ".xml";
using (var writer = new StreamWriter(path))
{
//if (staff == "k12Staff")
XNamespace ns = "http://specification.sifassociation.org/Implementation/na/3.2/html/CEDS/K12/K12_k12Staff.html";
var root = new XElement(ns + "k12Staff");
foreach (var d in doc.Descendants("staff"))
{
root.Add(new XElement(ns + "staff",
new XElement(ns + "identity",
new XElement(ns + "name",
new XElement(ns + "firstName", first),
new XElement(ns + "lastName", last)
)
),
new XElement(ns + "employment",
new XElement(ns + "positionTitle", position)
),
new XElement(ns + "assignment",
new XElement(ns + "leaID", leaID),
new XElement(ns + "schoolID", schoolID)
),
new XElement(ns + "contact",
new XElement(ns + "phoneNumberList",
new XElement(ns + "number", phone),
new XElement(ns + "phoneNumberIndicator", indicator)
),
new XElement(ns + "emailList",
new XElement(ns + "email", email)
)
),
new XElement(ns + "delete", delete)
Then if the staffType was something different such as "psStaff" then I would change the format of the XML (XElement) to have different names, positions, etc.
So it would be like:
if(staff == "k12Staff"){
format xml here...
}
else if (staff == "psStaff"){
format xml here....
}
etc etc..
My Problem:
In the previous example, my code has if(staff == "k12Staff") but I am told that it is an assigned local variable. I have tried declaring staff outside of the using statements as well as trying to use staff in a using statement like so using(staff) which is how I used my cmd variable. How come my program recognizes cmd but not staff?
You did not post the entire code, so it is not possble to say, where your variable staff should get a value and why it doesn't.
Not assigned means: existing but never got a value...
Try the following: At the place, where you declare your variable change this:
string staff="defaultValue";
On the place where you handle the variable's content change this:
if(staff == "k12Staff"){
format xml here...
}
else if (staff == "psStaff"){
format xml here....
}
else if (staff == "defaultValue"){
//What ever is to be done if all attempts to set "staff" did not work
//You must set a stop mark before your `while (!quit)` and step through.
//There is at least one situation, where `staff` is not set to any value...
//If there's a bug you must fix this, if this is allowed to happen, solve it here...
}
Related
I have the following code:
private string GetXmlBody()
{
XNamespace ns = "http://schemas.xmlsoap.org/soap/envelope/";
XNamespace xsdNs = "http://www.w3.org/2001/XMLSchema";
XNamespace xsiNs = "http://www.w3.org/2001/XMLSchema-instance";
XNamespace outNs = "http://soap.sforce.com/2005/09/outbound";
XNamespace sfNs = "urn:sobject.enterprise.soap.sforce.com";
XDocument requestXml = new XDocument(
new XElement(ns + "Envelope", new XAttribute(XNamespace.Xmlns + "soapenv", ns), new XAttribute(XNamespace.Xmlns + "xsd", xsdNs), new XAttribute(XNamespace.Xmlns + "xsi", xsiNs),
new XElement(ns + "Body",
new XElement(outNs + "notifications", new XAttribute("xmlns", outNs),
new XElement(outNs + "OrganizationId", runInfo.OrgId),
new XElement(outNs + "SessionId", runInfo.SessionId),
new XElement(outNs + "EnterpriseUrl", runInfo.Location),
new XElement(outNs + "Notification",
new XElement(outNs + "Id", "04l0H000014TY73QAG"),
new XElement(outNs + "sObject", new XAttribute(XNamespace.Xmlns + "sf", sfNs), new XAttribute(xsiNs + "type", "sf:" + runInfo.RecordType),
new XElement(sfNs + "Id", runInfo.RecordId),
new XElement(sfNs + runInfo.Field, runInfo.FieldValue)
)
)
)
)
)
);
return requestXml.ToString();
}
Which will generate XML needed however I'm running into the following error:
System.Xml.XmlException : The ':' character, hexadecimal value 0x3A, cannot be included in a name.
due to the value of runInfo.FieldValue which contains :. For Example the value may look like:
Opportunity:006i000000sidsh;Account:;userId:a016S00000sjsiq;sandbox:true
So far all the solutions or similar problems that I've seen revolve around producing the correct element name, my problem is around the value. If for instance I remove the : from the runInfo.FieldValue variable then the expected XML is produced.
Any thoughts on how to get around this? I've tried URL encoding the string but that just leads to a similar error except it complains about % values.
I wrote an application that would ask the user for some details of the hotel that they are staying at, and the text does luckily get added, but if I add another person it will override the previous data that was in the file already. However, I want it to keep all of the data inputs.
Here is my code:
hotelName = txt_HotelName.Text;
ratings = txt_HotelRating.Text;
roomsNeeded = txt_RoomsNeeded.Text;
name = txt_UserName.Text;
surname = txt_UserLastname.Text;
contactDetails = txt_ContactDetail.Text;
paymentDetails = txt_PaymentMehthod.Text;
paymentDate = txt_PaymentDate.Text;
using (StreamWriter sw = new StreamWriter("HotelDocument.txt"))
{
sw.WriteLine(txt_HotelName + Environment.NewLine + txt_HotelRating + Environment.NewLine + txt_RoomsNeeded +
Environment.NewLine + txt_UserName + Environment.NewLine + txt_UserLastname + Environment.NewLine + txt_ContactDetail +
Environment.NewLine + txt_PaymentMehthod + Environment.NewLine + txt_PaymentDate);
}
MessageBox.Show($"Thank you for using our system {txt_UserName.Text}.", "Thank you", MessageBoxButtons.OK);
So what I want is to collect all of the data, rather than having them over-write each time.
Try appending the file:
string line = string.Join(Environment.NewLine, new string[] {
ratings,
roomsNeeded,
name,
surname,
contactDetails,
paymentDetails,
paymentDate});
File.AppendAllLines("HotelDocument.txt", new string[] {line});
Edit: if you want to organize the input data, I suggest using string interpolation (C# 6.0) or formatting:
string line = string.Join(Environment.NewLine, new string[] {
$"Ratings: {ratings}",
$"Rooms need: {roomsNeeded}",
$"Name: {name}",
$"Surname: {surname}",
$"Details: {contactDetails}",
$"Payment: {paymentDetails}",
$"Payment Date: {paymentDate}");
You need to specify a unique name:
using (StreamWriter sw = new StreamWriter("HotelDocument.txt"))
So instead of "HotelDocument.txt" maybe use the current DateTime, or even a new Guid() to be 100% unique. So something like:
var uniqueFileName = new Guid().ToString() + ".txt";
using (StreamWriter sw = new StreamWriter(uniqueFileName))
Or are you looking to append new data within the existing HotelDocument.txt?
Having this Linq statement to create an XML
new XElement(ns + "SpecialRegisters",
from reg in registers
where reg.IsUpdateRegister
select new XElement(ns + "UpdateRegisters",
new XElement(ns + "RegID",
new XAttribute("ID", registers.IndexOf(reg).ToString().PadLeft(2, '0'))
)
)
)
Is it possible to create a unique UpdateRegisters element with multiple RegID.
If there are no update registers there should not exist any UpdateRegisters element.
You could do this instead:
var result=new XElement(ns + "SpecialRegisters");
var updateRegister=register.Where(e=>e.IsUpdateRegister);// To not repeat the same query twice
if(updateRegister.Count()>0)
{
result.Add( new XElement(ns + "UpdateRegisters",
updateRegister.Select((e,i)=> new XElement(ns + "RegID",i));
}
Update
If you want to do it all in the same statement then you could do this:
var updateRegister=register.Where(e=>e.IsUpdateRegister);// To not repeat the same query twice
var result=new XElement(ns + "SpecialRegisters", updateRegister.Any()?
new XElement(ns + "UpdateRegisters", updateRegister.Select((e,i)=> new XElement(ns + "RegID",i)):null );
My solution based on yours (miguelmpn)
Speed is not important, as I'm saving a simple and small file..
new XElement(ns + "SpecialRegisters", Registers.Registers.Singleton.Any(x => x.IsUpdateRegister) ?
new XElement(ns + "UpdateRegisters", Registers.Registers.Singleton.Where(e => e.IsUpdateRegister).Select((e, i)=> new XElement(ns + "RegID", i))) : null)
I think the one of Enumerable.Aggregate method overload fits for this task very well.
var specialRegisters =
new XElement(ns + "SpecialRegisters",
Registers.Registers.Singleton.Where(reg => reg.IsUpdateRegister)
.Select((reg, i) => new XElement(ns + "RegID", i))
.Aggregate(new XElement(ns + "UpdateRegisters"),
(upReg, reg) =>
{
upReg.Add(reg);
return upReg;
},
upReg => upReg.HasElements ? upReg : null));
This approach will enumerate collection only once.
Third parameter of Aggregate method is key value of this approach, which return null in case no elements was added.
My own opinion to comment: but my intention is to keep the code cleaner by having it all on the same linq query.
I think keeping this kind of logic in one statement is not clean approach. I think one of idea of cleanliness is that reader of your code will understand your intentions faster.
You can extract creating UpdateRegisters element to the dedicated method
private XElement CreateUpdateRegistersOrNullIfEmpty(XNamespace ns,
IEnumerable<YourType> data)
{
return data.Where(reg => reg.IsUpdateRegister)
.Select((reg, i) => new XElement(ns + "RegID", i))
.Aggregate(new XElement(ns + "UpdateRegisters"),
(upReg, reg) =>
{
upReg.Add(reg);
return upReg;
},
upReg => upReg.HasElements ? upReg : null));
}
Then use it
var specialRegisters =
new XElement(ns + "SpecialRegisters",
CreateUpdateRegistersOrNullIfEmpty(ns, Registers.Registers.Singleton));
How should I write code in C# to create xml file like this
<ymaps:GeoObjectCollection>
<gml:name>Something</gml:name>
<gml:featureMembers>
<ymaps:GeoObject>
<gml:name>Something</gml:name>
<gml:description>Something</gml:description>
<gml:LineString>
<gml:pos>50.588298 55.145683</gml:pos>
<gml:pos>50.588290 55.145678</gml:pos>
<gml:pos>50.588288 55.145678</gml:pos>
</gml:LineString>
<ymaps:style>#customStyle1</ymaps:style>
</ymaps:GeoObject>
this yandex's xml file, and it has xsd file on http://maps.yandex.ru/schemas/ymaps/1.x/ymaps.xsd
First familiarize yourself with XML, XML Namespaces, XML Schemas and how to process XML data in .NET. Once you have mastered the basics, use the XML Schema Definition Tool (Xsd.exe) to generate classes from the XSD and use it from within your application.
Here is a demonstration of how to create the desired XML using LINQ to XML. I have created two classes to store the data: GeoObject and Pos:
var geoObjects = new[] {
new GeoObject {
Name = "Something",
Description = "Something",
Line = new[] {
new Pos { X = 50.588298M, Y = 55.145683M },
new Pos { X = 50.588290M, Y = 55.145678M },
new Pos { X = 50.588288M, Y = 55.145678M }
},
Style = "#customStyle1"
}
};
The XML is created using this code:
XNamespace ymaps = "http://maps.yandex.ru/ymaps/1.x";
XNamespace gml = "http://www.opengis.net/gml";
var xElement = new XElement(
ymaps + "GeoObjectCollection",
new XAttribute(XNamespace.Xmlns + "ymaps", ymaps),
new XAttribute(XNamespace.Xmlns + "gml", gml),
new XElement(gml + "name", "Something"),
new XElement(gml + "featureMembers",
geoObjects.Select(
geoObject => new XElement(
ymaps + "GeoObject",
new XElement(gml + "name", geoObject.Name),
new XElement(gml + "description", geoObject.Description),
new XElement(gml + "LineString",
geoObject.Line.Select(
pos => new XElement(
gml + "pos",
String.Format(CultureInfo.InvariantCulture, "{0} {1}", pos.X, pos.Y)
)
)
),
new XElement(ymaps + "style", geoObject.Style)
)
)
)
);
If you write out xElement you get the following XML:
<ymaps:GeoObjectCollection xmlns:ymaps="http://maps.yandex.ru/ymaps/1.x" xmlns:gml="http://www.opengis.net/gml">
<gml:name>Something</gml:name>
<gml:featureMembers>
<ymaps:GeoObject>
<gml:name>Something</gml:name>
<gml:description>Something</gml:description>
<gml:LineString>
<gml:pos>50.588298 55.145683</gml:pos>
<gml:pos>50.588290 55.145678</gml:pos>
<gml:pos>50.588288 55.145678</gml:pos>
</gml:LineString>
<ymaps:style>#customStyle1</ymaps:style>
</ymaps:GeoObject>
</gml:featureMembers>
</ymaps:GeoObjectCollection>
I am inserting bulk data(serial number,pin number) to DB.Before inserting,the data from datatable is binded into XML tag.Here the pin number is encrypted one...as follows,
strXml = "<?xml<pre lang="c#"></pre> version=" + #"""1.0"" encoding=" + #"""iso-8859-1""?><batch>";
strPinXml =strPinXml + "<data cardid="+#"""" +strid+#""""+" pinnumber=" + #"""" + myRC4Engine.CryptedText + #"""" + "></data>";
strXml = strXml + strPinXml + "</batch>";
Problem is after inserting into db, to verify whether the actual pinnumber(encrypted format in db) is inserted, i decrypted the pinnumber and found that,
The first digit in all data are displaced by (’)single quote and last
digit for some pinnumber is empty (if the pinnumber is-œA_¡/Ì·ÞvËÛ
(ie)ending in Û for that pins last digit is empty).
Please note that i'am using SQL server 2000 in this application
Please provide the solution to resolve this issue
Result as follows
Pins before inserting into db
Pinnumber(While inserting)
(Encrypted format) --- (Decrypted format)
šA [¦,ȵØzËÚ --------- 7613051524692
œA ¡/Ì•ÞvËÛ --------- 1687765748683
™# X¦!Ï´ÝÎÛ --------- 4770086471383
žA Z¡+ɹÝwÏÒ --------- 3642720979218
•O Q¢(˹Þ{ËÛ --------- 8879412945686
ŸO^¡,ȶÝ}Î× --------- 2846751673342
Pins retrieved from db after insertion
Pinnumber (Retrieved from db) ---- Retrieved pinnumber
(Encrypted format) --------------- (Decrypted format)
A [¦,ȵØzËÚ ------------------- ’613051524692
A _¡/Ì•ÞvËÛ ------------------- ’68776574868
# X¦!Ï´ÝÎÛ ------------------ ’77008647138
A Z¡+ɹÝwÏÒ ----------------- ’642720979218
O Q¢(˹Þ{ËÛ ------------------- ’879412945686
O ^¡,ȶÝ}Î× ------------------ ’846751673342
Application coding as follows
try
{
RC4Engine myRC4Engine = new RC4Engine();
myRC4Engine.EncryptionKey = "ab48495fdjk4950dj39405fk";
strXml = "<?xml version=" + #"""1.0"" encoding=" + #"""iso-8859-1""?> <batch>";
foreach (DataRow lobjbaseBatchDetail in dt.Rows)
{
myRC4Engine.InClearText = lobjbaseBatchDetail[3].ToString();
myRC4Engine.Encrypt();
strCardid = lobjbaseBatchDetail[0].ToString();
strBatchid = lobjbaseBatchDetail[1].ToString();
strid = strCardid + strBatchid + lobjbaseBatchDetail[2].ToString();
strPinXml =strPinXml + "<data cardid="+#"""" +strid+#""""+
" pinnumber=" + #"""" + myRC4Engine.CryptedText + #"""" + "></data>";
}
strXml = strXml + strPinXml + "</batch>";
SqlParameter[] arrParam = new SqlParameter[1];
arrParam[0] = new SqlParameter("#BATCHUPLOAD_XML", SqlDbType.Text );
arrParam[0].Direction = ParameterDirection.Input;
arrParam[0].Value = strXml;
iResult = SqlHelper.ExecuteNonQuery(objTrans, CommandType.StoredProcedure, "test_proc", arrParam);
objTrans.Commit();
}
catch(Exception ex)
{
objTrans.Rollback();
throw new Exception("Upload failed :" + ex.Message);
}
procedure
create procedure test_proc
(
#BATCHUPLOAD_XML text
)
as
begin
DECLARE #idoc INT
EXEC sp_xml_preparedocument #idoc OUTPUT, #BATCHUPLOAD_XML
insert into test_table_new
SELECT cardid,pinnumber
FROM OPENXML (#idoc, '/batch/data')
WITH (cardid varchar(100) '#cardid', pinnumber nvarchar(200) '#pinnumber')
EXEC sp_xml_removedocument #idoc
end
You shouldn't write the xml by hand. Let C#'s LinqToXml do it for you and it won't make mistakes.
You could write it like:
try
{
RC4Engine myRC4Engine = new RC4Engine();
myRC4Engine.EncryptionKey = "ab48495fdjk4950dj39405fk";
XDocument doc = new XDocument(
new XDeclaration("1.0", "iso-8859-1", null),
new XElement("batch"));
foreach (DataRow lobjbaseBatchDetail in dt.Rows)
{
myRC4Engine.InClearText = lobjbaseBatchDetail[3].ToString();
myRC4Engine.Encrypt();
strCardid = lobjbaseBatchDetail[0].ToString();
strBatchid = lobjbaseBatchDetail[1].ToString();
strid = strCardid + strBatchid + lobjbaseBatchDetail[2].ToString();
XElement data = new XElement("data");
data.Add(new XAttribute("cardid", strid));
data.Add(new XAttribute("pinnumber", myRC4Engine.CryptedText));
doc.Root.Add(data);
}
SqlParameter[] arrParam = new SqlParameter[1];
arrParam[0] = new SqlParameter("#BATCHUPLOAD_XML", SqlDbType.Text );
arrParam[0].Direction = ParameterDirection.Input;
arrParam[0].Value = doc.Declaration.ToString() +
doc.ToString(SaveOptions.DisableFormatting);
iResult = SqlHelper.ExecuteNonQuery(objTrans, CommandType.StoredProcedure, "test_proc", arrParam);
objTrans.Commit();
}
catch(Exception ex)
{
objTrans.Rollback();
throw new Exception("Upload failed :" + ex.Message);
}
RC4-encrypted information is binary data, not text. CryptedText shouldn't be typed as string. To wrap binary data in XML, you probably want to use the binary data's BASE64 encoding.