I am writing an interface in a Web service that returns XML output. The output is queried from a MS SQL database by calling stored procedure. While the stored procedure itself is not returning XML, and I don't have any control over it, I need to return the result set as XML.
Right now, I'm using XmlWriter. Is there an easier, elegant way to do this?
StringBuilder sbLog = new StringBuilder();
XmlWriter writer = XmlWriter.Create(sbLog);
writer.WriteStartDocument();
writer.WriteStartElement("LogSet");
while (sqlRdr.Read())
{
writer.WriteStartElement("Log");
writer.WriteStartElement("EntryID");
writer.WriteValue(sqlRdr["EntryID"].ToString());
writer.WriteEndElement();
//and so on
Yeah XDocument is probably a cleaner interface. It would look something like this:
var doc = new XDocument(
new XElement("LogSet",
new XElement("EntryID", sqlRdr["EntryID"].ToString()),
new XElement(...)
)
);
// save it to a file
doc.Save(pathToDoc);
// or just return it
return doc.ToString();
I'm not sure about it's elegance (I guess that partially depends on how many times you need to reproduce this sort of thing in your code), but I wrote an XmlDataReader a while back that converts tabular data in an IDataReader into an Xml result without the need to create a secondary document/string. As WebServices could return an XmlNode (rather than XmlReader) the second class XmlNodeFactory does that conversion.
Here is the Gist for XmlDataReader
And for the XmlNodeFactory
Usage is something like:
[WebMethod]
public XmlNode GetFeaturedItems(string storeId)
{
var xmlReader = new XmlDataReader(
_db.GetFeaturedItems(storeId),
MyXmlNames.FeaturedItemsNamespace)
{
IncludeIndexField = false,
IncludeResultLevel = false,
RootElementName = "FeaturedItems",
RowElementNameFormat = "Item"
};
return XmlNodeFactory.Create(xmlReader);
}
Related
I'll try to keep it short and thank you in advance.
I have created a Quiz. The Questions and answers, as well as the integer for the correct answer are done via get and set , into a constructor and then created in another class by just creating an object and giving it the parameters. it looks as follows:
allQuestions = new Question[3];
allQuestions[0] = new Question("Question1", "answer1", "answer2",
"answer3", "answer4", 2);
where 2 is the integer that says answer 2 is the correct one.
i do use this array in almost every function in my code.
Now i decided to get the questions from a XML Document instead of creating them here. I'm a C# beginner so i played around and could not get it working.
my self made xml looks as follows :
<questions>
<question>
<ID>1</ID>
<questiontext>Peter</questiontext>
<answer1>der</answer1>
<answer2>da</answer2>
<answer3>21</answer3>
<answer4>lol</answer4>
</question>
<question>
<ID>2</ID>
<questiontext>Paul</questiontext>
<antwort1>dasistid2</antwort1>
<antwort2>27</antwort2>
<antwort3>37</antwort3>
<antwort4>47</antwort4>
</question>
</questions>
so 2 basic nodes (?)
can you explain me how to read that one and store it into my array so i can still use my e.g. "allQuestions.Question1" ? watched a youtube tutorial, quite a lot, could still not get it working in this project.
using visual studio 2017 , WPF , C#
There are a lot of ways to do what you are trying to do. I'll give you a dirty example of a manual solution, as well as a more automatic one that should work. Note that the automatic version won't use your constructor so unless you have an empty constructor defined it may not work for you.
Manual processing using XML Linq:
public IList<Question> ParseXml(string xmlString)
{
var result = new List<Question>();
var xml = XElement.Parse(xmlString);
var questionNodes = xml.Elements("question");
//If there were no question nodes, return an empty collection
if (questionNodes == null)
return result;
foreach (var questionNode in questionNodes)
{
var idNode = questionNode.Element("ID");
var textNode = questionNode.Element("questiontext");
var ant1Node = questionNode.Element("antwort1");
var ant2Node = questionNode.Element("antwort2");
var ant3Node = questionNode.Element("antwort3");
var ant4Node = questionNode.Element("antwort4");
var question = new Question();
question.Id = Convert.ToInt32(idNode?.Value);
// note the '?.' syntax. This is a dirty way of avoiding NULL
// checks. If textNode is null, it returns null, otherwise it
// returns the textNode.Value property
question.Text = textNode?.Value;
question.AnswerOne = ant1Node?.Value;
question.AnswerTwo = ant2Node?.Value;
question.AnswerThree = ant3Node?.Value;
question.AnswerFour = ant4Node?.Value;
result.Add(question);
}
return result;
}
Next we have the XmlSerializer approach. This is not ideal in all situations, but provides an easy way to serialize objects into XML and to deserialize XML into objects.
public QuestionCollection autoparsexml(string xml)
{
//create the serializer
XmlSerializer serializer = new XmlSerializer(typeof(QuestionCollection));
//convert the string into a memory stream
MemoryStream memStream = new MemoryStream(Encoding.UTF8.GetBytes(xml));
//deserialize the stream into a c# object
QuestionCollection resultingMessage = (QuestionCollection)serializer.Deserialize(memStream);
}
public class QuestionCollection
{
public List<Question> Questions { get; set; }
}
I don't realy understand how to read te predicates (URINodes) from a subject URINode.
Also, is there anyway to lookup IURINodes by specific predicates values?
I seem to have found my required methode on this post!
My solution:
//Path to RDF/XML file
pathToRDF = "c:\dotNetRdfExample\exampleRDF.xml"
// A IGraph Parser, implementing the IRdfReader interface (So it can work with RDF/XML formats)
RdfXmlParser rxpparser = new RdfXmlParser();
// Create a graph for the rdf data
Graph g = new Graph();
// Makes sure that the XML file is UTF8
StreamReader sr = new StreamReader(pathToRDF, true);
// Fill the empty IGraph, using the rdfXmlParser
rxpparser.Load(g, sr);
// Retrieve all triples with the specified predicate and object
IEnumerable<Triple> specificTriples = g.GetTriplesWithPredicateObject(g.CreateUriNode(UriFactory.Create("http://www.w3.org/1999/02/22-rdf-syntax-ns#type")),
g.CreateUriNode(UriFactory.Create("http://www.projectenportfolio.nl/wiki/index.php/Speciaal:URIResolver/Category-3AHandelingsperspectief")));
Are there any libraries in .Net to help compare and find differences between two json objects? I've found some solutions available for JavaScript, but nothing interesting for C#. The point of my question is to create json with changes marked in some way, based on the comparison. So that the user could see where the changes are.
using Microsoft.XmlDiffPatch;
using Newtonsoft.Json;
Convert each json to xml and use MS XmlDiff libary. Available on nuget. Differences are given in another xml doc which here I write to the console. This is suitable for unit testing for example.
public bool CompareJson(string expected, string actual)
{
var expectedDoc = JsonConvert.DeserializeXmlNode(expected, "root");
var actualDoc = JsonConvert.DeserializeXmlNode(actual, "root");
var diff = new XmlDiff(XmlDiffOptions.IgnoreWhitespace |
XmlDiffOptions.IgnoreChildOrder);
using (var ms = new MemoryStream())
using (var writer = new XmlTextWriter(ms, Encoding.UTF8))
{
var result = diff.Compare(expectedDoc, actualDoc, writer);
if (!result)
{
ms.Seek(0, SeekOrigin.Begin);
Console.WriteLine(new StreamReader(ms).ReadToEnd());
}
return result;
}
}
I have used different JSON objects than those in your example but it will apply to your case correctly.
private static string GetJsonDiff(string action, string existing, string modified, string objectType)
{
// convert JSON to object
JObject xptJson = JObject.Parse(modified);
JObject actualJson = JObject.Parse(existing);
// read properties
var xptProps = xptJson.Properties().ToList();
var actProps = actualJson.Properties().ToList();
// find differing properties
var auditLog = (from existingProp in actProps
from modifiedProp in xptProps
where modifiedProp.Path.Equals(existingProp.Path)
where !modifiedProp.Value.ToString().Equals(existingProp.Value.ToString())
select new AuditLog
{
Field = existingProp.Path,
OldValue = existingProp.Value.ToString(),
NewValue = modifiedProp.Value.ToString(),
Action = action, ActionBy = GetUserName(),
ActionDate = DateTime.UtcNow.ToLongDateString(),
ObjectType = objectType
}).ToList();
return JsonConvert.SerializeObject(auditLog);
}
I think your best bet is to use JSON.NET to create two JSON objects, then recursively loop through the tree, comparing each node to see if it exists and is equal while you go.
I think the best way to go here is to create objects using newtonsoft json.http://www.nuget.org/packages/newtonsoft.json/
So, you will have two objects of the same type, which you can easily compare and mark the differences.
private IEnumerable<JProperty> JSONCompare(string expectedJSON, string actualJSON)
{
// convert JSON to object
JObject xptJson = JObject.Parse(expectedJSON);
JObject actualJson = JObject.Parse(actualJSON);
// read properties
var xptProps = xptJson.Properties().ToList();
var actProps = actualJson.Properties().ToList();
// find missing properties
var missingProps = xptProps.Where(expected => actProps.Where(actual => actual.Name == expected.Name).Count() == 0);
return missingProps;
}
I'm trying to parse a json file and then operate on it to insert data into a SQL Server 2008 Database.
Example:
var sr = new StreamReader("C:\\path to file\file.json");
var json = JsonSerializer.SerializeToString(sr);
var o = JsonObject.Parse(json);
But I always get this error at the second line - "Timeouts are not supported on this stream."
The Json file looks like this:
"main":{
"prg": [
{
"Id": 1,
"name": "A&E",
more fields
}
"prg": [
{
"Id": 2,
"name": "asda",
more fields
}
}
I need to make something like this
foreach (prg in main)
entity.id = prg.id
entity.name = prg.name
How can I do this and why I get that timeout exception?
EDIT: To better understand my question this is how I do for an XML file
XmlDocument sourceDoc = new XmlDocument();
sourceDoc.Load(SourcesElement2); // where SourcesElement2 is the path to my XML
XmlNodeList prg = sourceDoc.GetElementsByTagName("prg");
foreach (XmlNode item in prg)
{
entity.Name= item.SelectSingleNode("name").InnerText;
...
}
I have converted the XML to Json and I want to do same thing. For every "prg" node in the Json File insert a new item in the database
EDIT2:
This is what I've done.
using (
StreamReader stream =
File.OpenText(
"C:\\path\\Sources.json")
)
{
JObject sources = (JObject) JToken.ReadFrom(new JsonTextReader(stream));
var a = sources["on"];
var b = a["sources"];
var c = b["prgs"];
foreach (var item in c)
{
var d= item.SelectToken("prg");
// Here d is null
}
I have the same question as the one from above. For every "prg" node in the Json File insert a new item in the database. How can I do this ? ( path to prg is on/sources/prgs/ )
I don't think you want to serialize the stream.
JsonSerializer.SerializeToString(sr)
You want to deserialize from the stream.
JsonSerializer.Deserialize
You might want to use JsonReader for performance reasons.
Your XML example load the whole file in the memory - you don't want to do that for large documents. reader.Read() pattern is better suited for processing large files.
For everyone with the same problem here is what I've done ( NOTE: this is just an example )
By the way, thank you for everyone who tried to answer my question and I'm sorry for my mistakes.
List<string> d = new List<string>();
using (
StreamReader stream =
File.OpenText(
"C:\\path\\Sources.json")
)
{
JObject sources = (JObject) JToken.ReadFrom(new JsonTextReader(stream));
var a = sources["on"];
var b = a["sources"];
var c = b["prgs"];
foreach (JObject item in c["prg"].ToList())
{
d.Add(item.Value<string>("name"));
}
}
//part below is just for testing
foreach (var VARIABLE in d)
{
Console.WriteLine(VARIABLE);
}
Console.ReadLine();
I would approach it by converting that JSON object into a C# class and then applying logic to the C# object and/or use DataTables
[Note: There are solutions online that show you would to easily pass an Object or List<Object> into a DataTable and then pass it "easily" to SQL]
The first step is still your hiccup in either solution, how do I pull in a large JSON string from filesystem?
if you have the JSON, use json2csharp.com and/or jsonutils.com to retrieve the classes in order to Deserialize it to your object.
StreamReader re = new StreamReader(#"C:\path to file\file.json");
JsonTextReader reader = new JsonTextReader(re);
YourClass DeserializedObject = se.Deserialize<YourClass>(reader);
Console.WriteLine(DeserializeObject.SomeProperty);
This question may be asked or answered before but I feel that none of the hits really apply.
I would like to create a little class with attributes which will correspond to name and attributes in a output familiar to xml stream. The class should help the program to create a xml-alike string.
string test = "<graph caption='SomeHeader' attribute9='#someotherinfo'>" +
"<set name='2004' value='37800' color='AFD8F8' />" +
"<set name='2005' value='21900' color='F6BD0F' />" +
"<set name='2006' value='32900' color='8BBA00' />" +
"<set name='2007' value='39800' color='FF8E46' />" +
"</graph>";
I think you got the idea. I have a static amount of known attributes which will be used in the tags. The only Tags here is set and graph.
I would like to do something like this,
Helper o = new Helper()
List<Tag> tag = new List<Tag>();
foreach (var someitem in somedatabaseresult)
{
tag.Add(New Graph() { Caption = someitem.field , attribute9 = someitem.otherField });
foreach (var detail in someitem)
{
tag.Add(new Set() { name = detail.Year, value = detail.Value color = detail.Color });
}
}
o.Generate(); // Which will create the structure of result sample above
// and for future extension..
// o.GenerateXml();
// o.GenerateJson();
Please remember that this code is pesudo, just taken from my head. A result of that I have some ideas but it take a day to code and test what best (or whorse).
What would be best practice to solve this task?
[EDIT]
This mysterious "Helper" is the (unluckily typed) class who contains a list of Graph, a list of Set and also (what I think about) contains all available attributes per Graph/Set object. The work of the foreach-loops above are mentioned to fill the Helper class with the data.
[EDIT2]
Result here,
https://gist.github.com/1233331
Why not just create a couple of classes: Graph and Set. Graph would have a property of List<Set>.
In your foreach you can then create an instance or Graph and add instances of Set to its list.
When you're done use the XML Serializer to serialize the Graph object out to XML. Nice and easy to then output to another format as well if your needs change later e.g. serialize to JSON.
Edit following comment:
From top my head so may not be 100% correct...
var myGraph = BuildMeAGraph();
var serializer = new XmlSerializer(typeof(Graph));
var writer = XmlWriter.Create("myfile.xml");
serializer.Serialize(writer, myGraph);
But something like that should write it out to a file. If you want the XML in memory then write it out to an XMLTextWriter based on a memory stream instead and then you can write the contents to a string variable or do whatever you need with it.
If you want to create an XML, out of the object tree, then I think, you could try this:
XDocument doc = new XDocument
(
somedatabaseresult.Select
( someitem =>
new XElement("graph",
new XAttribute("Caption", ""),
new XAttribute("attribute9", "#something"),
someitem.Select
(detail =>
new XElement("Set",
new XAttribute("name", "2003"),
new XAttribute("value", "34784"),
new XAttribute("color", "#003300")
)
)
);
//save to file as XML
doc.Save("output.xml");
//save to local variable as XML string
string test = doc.ToString();
I wrote the save value for tags, as you've used in your code. However, I think you would like this:
new XAttribute("name", detail.name),
new XAttribute("value", detail.value),
new XAttribute("color", detail.color)
Or whatever value you want to give to each attribute from the object detail.
Use the XmlSerializer.
I'd use the ExpandoObject, but I don't see the reason for what you are doing.