I want to write a string into one Column in an .csv (Excel) file. My Problem is that the string is written into multiple Columns.
In this screenshot for example I have 20 Columns.
GetMetadataCompleteResponse resultValue = null;
string jsonData = null;
await Task.Run(() =>
{
byte[] rawData = Convert.FromBase64String(responseContent);
jsonData = CompressUtil.Unzip(rawData);
});
resultValue = JsonConvert.DeserializeObject<GetMetadataCompleteResponse>(jsonData);
foreach(string a in resultValue.Value.Values)
{
foreal += a;
}
await Log.Info("callWebservice for " + strUrl + ", Result: " + objErrorDetails.Code + ", " + foreal);
edit
I've noticed that the new Column starts after every ';'(semicolon). I probably can just replace it with something else.
I think you have 2 issues. The first one is how you write your CSV with simple string concatenation. With no escaping or double quote.
The Json will have commas , that will be separator in your CSV.
In order to produc e a valid CSV you should read the RFC 4180 and use a proper library to handle the Serialisation.
Here is an Minimal, Complete, and Verifiable example of writing a Json in a CSV column.
using CsvHelper;
using CsvHelper.Configuration;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
public class Program
{
public static void Main()
{
var input = new Foo
{
Label = "My Foo",
Bars = new List<Bar> {
new Bar{Label="Bar2"},
new Bar{Label="Bar1"},
new Bar{Label="Bar3"},
}
};
var json = JsonConvert.SerializeObject(input);
var myObject = new CsvObject
{
Label = "My CSV object",
FooString = json,
};
var result = "";
// Writing into a string instead of a file for debug purpuse.
using (var stream = new MemoryStream())
using (var reader = new StreamReader(stream))
using (var writer = new StreamWriter(stream))
using (var csv = new CsvWriter(writer))
{
csv.Configuration.RegisterClassMap<CsvObjectMap>();
csv.WriteHeader<CsvObject>();
csv.NextRecord();
csv.WriteRecord(myObject);
csv.NextRecord();
writer.Flush();
stream.Position = 0;
result = reader.ReadToEnd();
}
Console.WriteLine(result);
}
private sealed class CsvObjectMap : ClassMap<CsvObject>
{
public CsvObjectMap()
{
Map( m => m.FooString );
Map( m => m.Label );
}
}
public class CsvObject
{
public string Label { get; set; }
public string FooString { get; set; }
}
public class Foo
{
public string Label { get; set; }
public List<Bar> Bars { get; set; }
}
public class Bar
{
public string Label { get; set; }
}
}
Live demo : https://dotnetfiddle.net/SNqZX1
In this exemple I have used CsvHelper for CSV serialisation, and Json.NET for the Json serialisation. Note that Writing a CSV to a file is a more simlpe task that to a string like in this example
Related
My application reads .CSV file(which do not having a header in csv file) and converts into XML file.
For existing code wrote as
sr = new StreamReader(fs);
fs = null;
using (CsvReader csvReader = new CsvReader(sr))
{
sr = null;
csvReader.Configuration.HasHeaderRecord = hasHeaderRecord;
csvReader.Configuration.IgnoreBlankLines = false;
csvReader.Configuration.IgnoreReadingExceptions = true;
csvReader.Configuration.WillThrowOnMissingField = false;
csvReader.Configuration.TrimFields = true;
csvReader.Configuration.RegisterClassMap<Class1Map>();
FileRecords = csvReader.GetRecords<Class1>().ToList();
}
public class Class1Map : CsvClassMap<Class1>
{
public Class1Map()
{
Map(m => m.AccountId).Index(0);
Map(m => m.MeterId).Index(1);
.......
.......
}
}
But now for my new requirement, .csv file includes header and column names that are different compared to previous .csv. Somehow I have read the new CSV file and get values present in the csv file and mapped to class1.
Class1 properties are AccountId,MeterId etc.
But in new format the names are different now.
AccountId as AccountRef and MeterId as MeterSerial.
Can any one suggest how to map new file values of AccountRef,MeterSerial to class1 properties AccountId,MeterId
You could just add .Name() to your maps. Your first example with no header will use .Index() and your second example with a header will use .Name() to map the columns.
void Main()
{
var config1 = new CsvConfiguration(CultureInfo.InvariantCulture)
{
HasHeaderRecord = false
};
using (var reader = new StringReader("1,2\n3,4"))
using (var csv = new CsvReader(reader, config1))
{
csv.Context.RegisterClassMap<Class1Map>();
var records = csv.GetRecords<Class1>().Dump();
}
var config2 = new CsvConfiguration(CultureInfo.InvariantCulture)
{
HasHeaderRecord = true
};
using (var reader = new StringReader("MeterSerial,AccountRef\n4,5\n6,7"))
using (var csv = new CsvReader(reader, config2))
{
csv.Context.RegisterClassMap<Class1Map>();
var records = csv.GetRecords<Class1>().Dump();
}
}
public class Class1Map : ClassMap<Class1>
{
public Class1Map()
{
Map(m => m.AccountId).Index(0).Name("AccountRef");
Map(m => m.MeterId).Index(1).Name("MeterSerial");
}
}
public class Class1
{
public int AccountId { get; set; }
public int MeterId { get; set; }
}
I've found that function that correctly work for the JSON parse:
var objs = JObject.Load(new JsonTextReader(new StreamReader(JsonPath)))
.SelectTokens("*")
.Select(t => JsonConvert.DeserializeObject<Cars>(t.ToString()));
but it doesn't release the file after use it (so I can not use it for other function) ... I've tried to use the function Close, but seems not working over the object!
P.s. i've checked the previous open-one question, releated to this topic, but nobody talk about how to access to the object fileds, and seems the qeustion are different if we count that i have more than 1 object ... guess someone can explain better how it works ...
From the JSON.NET Site Read JSON from a File :
// read JSON directly from a file
using (StreamReader file = File.OpenText(#"c:\videogames.json"))
using (JsonTextReader reader = new JsonTextReader(file))
{
JObject o2 = (JObject)JToken.ReadFrom(reader);
}
The question's code does something unnecessary though - it tries to serialize the already deserialized JObject back into JSON, then deserialize it again as a Car. Why not deserialize the original file just once?
The docs describe this too in Deserialize JSON from a file:
// deserialize JSON directly from a file
using (StreamReader file = File.OpenText(#"c:\movie.json"))
{
JsonSerializer serializer = new JsonSerializer();
Movie movie2 = (Movie)serializer.Deserialize(file, typeof(Movie));
}
JSON documents can contain only a single object. If the file contents look like this :
{
"Movies":[{
"Title":"abc"
}, {
"Title":"abc"
}]
}
The root object should contain a Movies property that holds a Movie[] array :
class RootObjedt
{
public Movie[] Movies{get;set;}
}
...
using (StreamReader file = File.OpenText(#"c:\movie.json"))
{
JsonSerializer serializer = new JsonSerializer();
var root = (Movie)serializer.Deserialize(file, typeof(RootObject));
var movies=root.Movies;
}
I recommend you to read your json data async because this method have overload that takes stream as an input, so you can read data in two strings of code like this:
ProjFolder\Program.cs
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
using StackOverflow.Models;
namespace StackOverflow
{
class Program
{
static async Task Main(string[] args)
{
using var openStream = File.OpenRead(#"D:\Code\test.json");
var result = await JsonSerializer.DeserializeAsync<Root>(openStream);
// You need to get car2 Costo
var costo = result.Car2.Costo;
}
}
}
ProjFolder\Models\Root.cs
using System.Text.Json.Serialization;
namespace StackOverflow.Models
{
public class Root
{
[JsonPropertyName("car1")]
public Car Car1 { get; set; }
[JsonPropertyName("car2")]
public Car Car2 { get; set; }
}
}
ProjFolder\Models\Car.cs
namespace StackOverflow.Models
{
public class Car
{
public string CasaAutomobilistica { get; set; }
public string Modello { get; set; }
public string AnnoImmatricolazione { get; set; }
public string Targa { get; set; }
public int KM { get; set; }
public bool Finanziamento { get; set; }
public int Porte { get; set; }
public int Costo { get; set; }
}
}
{
"car1":
{
"CasaAutomobilistica": "Fiat",
"Modello": "500",
"AnnoImmatricolazione": "2017",
"Targa": "AZ978AG",
"KM": 120000,
"Finanziamento" : true,
"Porte" : 5,
"Costo" : 6000
},
"car2":
{
"CasaAutomobilistica": "BMW",
"Modello": "Serie 1",
"AnnoImmatricolazione": "2019",
"Targa": "BC978AG",
"KM": 150000,
"Finanziamento" : false,
"Porte" : 3,
"Costo" : 12000
}
}
First, read the file with surrounded by using block and do JSON operation
Better place it in a separate method as below
private string readFile()
{
string buffer = null;
using (System.IO.FileStream stm = new
System.IO.FileStream("c:\\YourFile.txt",System.IO.FileMode.Open,
System.IO.FileAccess.Read, System.IO.FileShare.None))
{
using (System.IO.StreamReader rdr = new System.IO.StreamReader (stm))
{
buffer=rdr.ReadToEnd();
}
}
return buffer
}
private Object Deserialize(string content)
{
//do conversion here
}
I'm using CSVHelper library for parsing CSV files, but I have to map tow columns to a single one that contains the data for each one: like {name}: {firstName} {lastName}
Is there any way to do that?
Thanks
Does this do what you were looking for?
public class Program
{
public static void Main(string[] args)
{
using (MemoryStream stream = new MemoryStream())
using (StreamWriter writer = new StreamWriter(stream))
using (StreamReader reader = new StreamReader(stream))
using (CsvReader csv = new CsvReader(reader, CultureInfo.InvariantCulture))
{
writer.WriteLine("Id,FirstName,LastName");
writer.WriteLine("1,Bob,Barker");
writer.WriteLine("2,Davey,Jones");
writer.Flush();
stream.Position = 0;
csv.Configuration.RegisterClassMap<FooClassMap>();
var records = csv.GetRecords<Foo>().ToList();
}
}
}
public class FooClassMap : ClassMap<Foo>
{
public FooClassMap()
{
Map(m => m.Id);
Map(m => m.Name).ConvertUsing(row => row.GetField("FirstName") + " " + row.GetField("LastName"));
}
}
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
}
I have the following object structure and trying to write to csv using csvhelper. but the filenames column in not getting added.
public class ClusterData
{
public IEnumerable<string> FileName { get; set; }
public int? ClusterNumber { get; set; }
public string TopTerm { get; set; }
}
using (var writer = new StreamWriter(#"C:\Clean.csv"))
{
var csv = new CsvWriter(writer);
csv.WriteHeader<ClusterData>();
foreach (var item in dataToCsv)
{
foreach (var filename in item.FileName)
{
csv.WriteField(filename);
csv.WriteField(item.ClusterNumber);
csv.WriteField(item.TopTerm);
csv.NextRecord();
}
}
writer.Flush();
}
how to achieve with this?i want the outer loop to be repeated once and inner loop to be repeated for each item in filename.
Thanks
Extract the desired data and then use the writer to send it to file
using (var writer = new StreamWriter(#"C:\Clean.csv")) {
var data = new List<ClusterData>();
//...assuming data is poulated
var dataToCsv = data.SelectMany(item => item.FileName.Select(filename => new {
FileName = filename,
ClusterNumber = item.ClusterNumber,
TopTerm = item.TopTerm
}));
var csv = new CsvWriter(writer);
csv.WriteRecords(dataToCsv);
}
A linq query is used to construct the desired object format for each file name in the data.
The data is then converted to CSV as it normally would using a CsvWriter
I have this XML file which have 3 Words.
<synset id="n00252662" type="n">
<lex_filenum>04</lex_filenum>
<word lex_id="1">purge</word>
<word lex_id="1">purging</word>
<word lex_id="1">purgation</word>
<pointer refs="n01247647">Hypernym</pointer>
<pointer refs="v00905283" source="3" target="1">Derivationally related form</pointer>
<pointer refs="v00475647" source="2" target="1">Derivationally related form</pointer>
<pointer refs="v00475819" source="1" target="2">Derivationally related form</pointer>
<pointer refs="v00905283" source="1" target="1">Derivationally related form</pointer>
<pointer refs="n00252894">Hyponym</pointer>
<def>the act of clearing yourself (or another) from some stigma or charge</def>
</synset>
And DictionaryList.cs
using System.Collections.Generic;
using System.Xml.Serialization;
using System.Xml;
using UnityEngine;
using System.IO;
[XmlRoot("DictionaryList")]
public class DictionaryList
{
[XmlArray("synsets")]
[XmlArrayItem("synset")]
public List<Dictionary> Dict = new List<Dictionary>();
//string filepath = Application.dataPath + "/Resources/gamedata.xml";
public static DictionaryList Load(string path)
{
var serializer = new XmlSerializer(typeof(DictionaryList));
using (var stream = new FileStream(path, FileMode.Open))
{
return serializer.Deserialize(stream) as DictionaryList;
}
}
//Loads the xml directly from the given string. Useful in combination with www.text.
public static DictionaryList LoadFromText(string text)
{
var serializer = new XmlSerializer(typeof(DictionaryList));
return serializer.Deserialize(new StringReader(text)) as DictionaryList;
}
}
Then The Dictionary.cs
using System.Xml;
using System.Xml.Serialization;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
public class Dictionary
{
public string word;
public string def;
public string example;
public Dictionary()
{
}
public Dictionary(string nme, string Des)
{
word = nme;
def = Des;
}
}
In my Code, the deserializer does not Include the word purging and purgation since the word <- variable is not an Array.
I have tried to make it an array List but I am not sure if the the deserializer will even put the other words if I make an List array word to it.
Plus accessing the the List inside the list is giving me a problem. I want to know if there is an option I can take where I can access or even store the word as an array without altering the XML file.
And this is my main Dictionary file
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
using System.Linq;
using UnityEngine.UI;
public class MainDictionary : MonoBehaviour {
DictionaryList DictionaryCollectionNoun;
DictionaryList DictionaryCollectionVerb;
DictionaryList DictionaryCollectionADV;
public InputField SearchField;
public Text NameField;
public Text DetailsField;
public Text DebugText;
public Text ExampleField;
public TextAsset textAssetNoun;
public TextAsset textAssetVerb;
public TextAsset textAssetADV;
// Use this for initialization
void Start () {
//TextAsset textAsset = (TextAsset)Resources.Load("datanoun", typeof(TextAsset));
//XmlDocument xmldoc = new XmlDocument ();
//xmldoc.LoadXml ( textAsset.text );
DebugText.text = Application.dataPath;
textAssetNoun = (TextAsset)Resources.Load("datanoun");
textAssetVerb = (TextAsset)Resources.Load("dataverb");
textAssetADV = (TextAsset)Resources.Load("dataadv");
//XmlDocument xmldoc = new XmlDocument();
//xmldoc.LoadXml(textAsset.text);
//Example Psuedocode Danzee Mode;
//var xmlData = #"<DictionaryList><synsets><synset><word>test</word><def>Fun</def></synset></synsets></DictionaryList>";
DictionaryCollectionNoun = DictionaryList.LoadFromText(textAssetNoun.text);
DictionaryCollectionVerb = DictionaryList.LoadFromText(textAssetVerb.text);
DictionaryCollectionADV = DictionaryList.LoadFromText(textAssetADV.text);
//Debug.Log(Application.dataPath);
//DebugText.text = xmldoc.ToString();
}
public void ChangeSearch()
{
//Dictionary Result = new Dictionary("No Result", "No Description");
//bool nounBool = DictionaryCollectionNoun.Dict.Any(p => p.word == SearchField.text.ToLower()) ? true : false;
//bool verbBool = DictionaryCollectionVerb.Dict.Any(p => p.word == SearchField.text.ToLower()) ? true : false;
//bool advbool = DictionaryCollectionADV.Dict.Any(p => p.word == SearchField.text.ToLower()) ? true : false;
//if (nounBool)
//{
// Result = DictionaryCollectionNoun.Dict.Find(x => x.word == SearchField.text.ToLower());
//}
//else if (verbBool)
//{
// Result = DictionaryCollectionVerb.Dict.Find(x => x.word == SearchField.text.ToLower());
//}
//else if (advbool)
//{
// Result = DictionaryCollectionADV.Dict.Find(x => x.word == SearchField.text.ToLower());
//}
//NameField.text = Result.word1;
//DetailsField.text = Result.def2;
//ExampleField.text = Result.example;
}
}
Try the following:
public class Word
{
[XmlAttribute("lex_id")]
public string LexId { get; set; }
[XmlText]
public string Value { get; set; }
public override string ToString()
{
return Value;
}
public static explicit operator string(Word word)
{
if (word == null)
return null;
return word.Value;
}
}
public class SynsetPointer
{
[XmlAttribute("refs")]
public string Refs { get; set; }
[XmlAttribute("source")]
public string Source { get; set; }
[XmlAttribute("target")]
public string Target { get; set; }
[XmlText]
public string Value { get; set; }
}
[XmlRoot("synset")]
[XmlType("synset")]
public class Synset
{
public Synset()
{
this.Pointers = new List<SynsetPointer>();
this.Words = new List<Word>();
}
[XmlElement("lex_filenum")]
public int LexFilenum { get; set; }
[XmlElement("word")]
public List<Word> Words { get; set; }
[XmlIgnore]
public IEnumerable<string> WordValues { get { return (Words == null ? null : Words.Select(w => (string)w)); } }
[XmlElement("pointer")]
public List<SynsetPointer> Pointers { get; set; }
[XmlElement("def")]
public string Definition { get; set; }
}
[XmlRoot("DictionaryList")]
public class DictionaryList
{
public DictionaryList()
{
this.Dict = new List<Synset>();
}
[XmlArray("synsets")]
[XmlArrayItem("synset")]
public List<Synset> Dict { get; set; }
//string filepath = Application.dataPath + "/Resources/gamedata.xml";
public static DictionaryList Load(string path)
{
var serializer = new XmlSerializer(typeof(DictionaryList));
using (var stream = new FileStream(path, FileMode.Open))
{
return serializer.Deserialize(stream) as DictionaryList;
}
}
//Loads the xml directly from the given string. Useful in combination with www.text.
public static DictionaryList LoadFromText(string text)
{
var serializer = new XmlSerializer(typeof(DictionaryList));
return serializer.Deserialize(new StringReader(text)) as DictionaryList;
}
}
I renamed your Dictionary class to Synset for clarity, since c# already has various dictionary classes which do something different.
To read multiple word elements into an array, declare it as a List<Word> in the Synset class, then apply the [XmlElement] attribute. This tells the serializer to expect repeated occurrences of the word element rather than a nested list of elements.
This will successfully read and write XML that looks like this:
<DictionaryList>
<synsets>
<synset>
<lex_filenum>4</lex_filenum>
<word lex_id="1">purge</word>
<word lex_id="1">purging</word>
<word lex_id="1">purgation</word>
<pointer refs="n01247647">Hypernym</pointer>
<pointer refs="v00905283" source="3" target="1">Derivationally related form</pointer>
<pointer refs="v00475647" source="2" target="1">Derivationally related form</pointer>
<pointer refs="v00475819" source="1" target="2">Derivationally related form</pointer>
<pointer refs="v00905283" source="1" target="1">Derivationally related form</pointer>
<pointer refs="n00252894">Hyponym</pointer>
<def>the act of clearing yourself (or another) from some stigma or charge</def>
</synset>
</synsets>
</DictionaryList>
Update
To loop through all the text values of all the Word classes in all the Synset classes in a DictionaryList, you can do:
var testXml = #"<DictionaryList> <synsets> <synset id=""n00001740"" type=""n""> <lex_filenum>03</lex_filenum> <word lex_id=""0"">entity</word> <pointer refs=""n00001930 n00002137 n04424418"">Hyponym</pointer> <def>that which is perceived or known or inferred to have its own distinct existence (living or nonliving)</def> </synset> </synsets> </DictionaryList>";
var dict = DictionaryList.LoadFromText(testXml);
foreach (var synSet in dict.Dict)
{
var words = synSet.WordValues.ToList();
var word0 = (words.Count > 0 ? words[0] : null);
var word2 = (words.Count > 2 ? words[2] : null);
// Do something with the words.
}
Update 2
To search for a Synset containing a given word, you can do:
var word = "entity";
var Results = dict.Dict.Where(s => s.WordValues.Any(w => w == word)); // Find all synsets containing the word "entity"
var Result = dict.Dict.FirstOrDefault(s => s.WordValues.Any(w => w == word)); // Find the first synsets containing the word "entity"