looks like a very simple task by i'm very new to c# and can't seem to find the right answer for this
i have the below xml structure (elements vary in quantity)
<config>
<extras>
<dir_update>C:\extension\update.exe</dir_update>
</extras>
<connection_MAIN>
<ip>LOCALHOST,1433</ip>
<bd>DATA</bd>
<user>sa</user>
<password>gzqs=</password>
</connection_MAIN>
<connection_LOBBY>
<ip>10.0.0.2,1433</ip>
<bd>DATA</bd>
<user>sa</user>
<password>I/wqqZIgzqs=</password>
<caixa>5yIz5GPu80s=</caixa>
<printer>cARrmGLQlztLiUDxIJqoPkvJabIiyI9ye4H7t+4muYk=</printer>
</connection_LOBBY>
<connection_FRONT>
<ip>10.0.0.5,1433</ip>
<bd>FIELDS</bd>
<user>sa</user>
<password>I/wqqZIgzqs=</password>
</connection_FRONT>
</config>
I'm already getting the elements that start with "connection_" in my combobox and i want the values inside the <ip>, <bd>, <user> and <password> when i select the connection on the combobox.
The problem i'm getting is that it's returning the word itself not the value inside on the code below
private void Form1_Load(object sender, EventArgs e)
{
using(DataSet ds = new DataSet())
{
ds.ReadXml(textBox1.Text);
foreach(DataTable dt in ds.Tables)
{
if (dt.ToString().Contains("conection_"))
{
comboBox1.Items.Add(dt.ToString().Replace("conection_", ""));
}
}
comboBox1.SelectedIndex = 0;
}
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
using(DataSet ds = new DataSet())
{
ds.ReadXml(textBox1.Text);
string v = comboBox1.Text.ToString();
string ip = ds.Tables[$"conection_{v}"].Columns[0].ToString();
}
}
Variable ip is getting the value "ip" and i want "LOCALHOST,1433" when i select the first option on my combobox in this example.
Also i want to search for column value by the name ("ip", "bd"), but i seem to only get results when using Columns[0], Columns[1].
I've followed some guides that i've looked around, but they seem to not work on this format of xml or i'm looking at it the wrong way.
Any help is appreciated.
There is no need to use DataSet and DataTable data types. The best API to handle XML is LINQ to XML.
Check it out below.
c#
void Main()
{
const string MAIN = "connection_MAIN";
string IP = string.Empty;
string bd = string.Empty;
string user = string.Empty;
string password = string.Empty;
XElement xml = XElement.Parse(#"<config>
<extras>
<dir_update>C:\extension\update.exe</dir_update>
</extras>
<connection_MAIN>
<ip>LOCALHOST,1433</ip>
<bd>DATA</bd>
<user>sa</user>
<password>gzqs=</password>
</connection_MAIN>
<connection_LOBBY>
<ip>10.0.0.2,1433</ip>
<bd>DATA</bd>
<user>sa</user>
<password>I/wqqZIgzqs=</password>
<caixa>5yIz5GPu80s=</caixa>
<printer>cARrmGLQlztLiUDxIJqoPkvJabIiyI9ye4H7t+4muYk=</printer>
</connection_LOBBY>
<connection_FRONT>
<ip>10.0.0.5,1433</ip>
<bd>FIELDS</bd>
<user>sa</user>
<password>I/wqqZIgzqs=</password>
</connection_FRONT>
</config>");
// get needed connection fragment
IEnumerable<XElement> fragment = xml.Descendants(MAIN);
// get all needed elements one by one
IP = fragment.Elements("ip")?.FirstOrDefault().Value;
bd = fragment.Elements("bd")?.FirstOrDefault().Value;
user = fragment.Elements("user")?.FirstOrDefault().Value;
password = fragment.Elements("password")?.FirstOrDefault().Value;
}
Using Xml Linq I put results in to a datatable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("name", typeof(string));
dt.Columns.Add("ip", typeof(string));
dt.Columns.Add("bd", typeof(string));
dt.Columns.Add("user", typeof(string));
dt.Columns.Add("password", typeof(string));
XDocument doc = XDocument.Load(FILENAME);
foreach(XElement connection in doc.Descendants().Where(x => x.Name.LocalName.StartsWith("connection_")))
{
dt.Rows.Add(new object[] {
((string)connection.Name.LocalName).Substring(((string)connection.Name.LocalName).IndexOf("_") + 1),
(string)connection.Element("ip"),
(string)connection.Element("bd"),
(string)connection.Element("user"),
(string)connection.Element("password")
});
}
Dictionary<string, DataRow> dict = dt.AsEnumerable()
.GroupBy(x => x.Field<string>("name"), y => y)
.ToDictionary(x => x.Key, y => y.FirstOrDefault());
string ip = dict["LOBBY"].Field<string>("ip");
}
}
}
Related
I need to export some parameters of a family type from a Revit document to ms-access using C# programming.
I googled and read several pages, and I watched several videos. Then I wrote the following code. But it doesn't work. (I also checked all settings to connect of Revit API) Could anyone help me, please?
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.Attributes;
using System.Data.OleDb;
namespace MyRevitCommands
{
[TransactionAttribute(TransactionMode.ReadOnly)]
public class GetWindows : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements, params string[] parameters)
{
//Get Document
Document oDoc = commandData.Application.ActiveUIDocument.Document;
//Get UIDocument
UIDocument uidoc = new UIDocument(oDoc);
//Create Filtered Element Collector
FilteredElementCollector WinCollector = new FilteredElementCollector(oDoc).OfClass(typeof(FamilyInstance)).OfCategory(BuiltInCategory.OST_Windows);
//Create Filter
ElementCategoryFilter filter = new ElementCategoryFilter(BuiltInCategory.OST_Windows);
IList<Element> windows = WinCollector.WherePasses(filter).WhereElementIsNotElementType().ToElements();
TaskDialog.Show("Windows", string.Format("{0} windows counted!", windows.Count));
private Document oDoc;
// parameters for database connection
private OleDbConnection myAccessConn;
private string connectionString;
private OleDbDataAdapter Adapter;
public DataSet myDataset = new DataSet();
private ModelItemCollection MySearchResult = new ModelItemCollection();
{
oDoc = Document;
MySearchResult = oDoc.CurrentSelection.SelectedItems;
DataTable Mydatatable = new DataTable();
DataRow MyDataRow;
try
{
connectionString = ("Provider=Microsoft.ACE.OLEDB.12.0;" + ("Data Source=" + "D:\\Data.accdb"));
myAccessConn = new OleDbConnection(connectionString);
myAccessConn.Open();
Adapter = new OleDbDataAdapter("SELECT * FROM Windows;", myAccessConn);
Adapter.Fill(myDataset, "Windows");
Mydatatable = myDataset.Tables["Windows"];
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString);
}
int counter = 0;
string str;
DataProperty classproperty;
Mydatatable.Clear();
foreach (Element e in WinCollector)
{
counter=counter+1
MyDataRow = Mydatatable.NewRow;
}
return Result.Succeeded;
}
}
}
}
I guess you put the data in inside this foreach
foreach (Element e in WinCollector)
{
//Get the value from the parameter
string paramValue = e.LookupParameter("parameter_name").AsValueString();
counter=counter+1
MyDataRow = Mydatatable.NewRow;
//Set the value in the data table
MyDataRow["some_col"] = paramValue;
}
For more information about the revit API check this link.
Here is my schema of xml.
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfResultstring xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Resultstring>
<Key>Blablabla : </Key>
<Values>
<string>79,0441326460292</string>
<string>76,0959542079328</string>
<string>74,3061819154758</string>
<string>78,687039788779</string>
</Values>
<Type>list</Type>
</Resultstring>
<Resultstring>
<Key>Blablabla : </Key>
<Values>
<string>87,7110395931923</string>
</Values>
<Type>double</Type>
</Resultstring>
</ArrayOfResultstring>
I need read this XML file and fill the datatable.
I'm trying with DataSet.
DataSet ds = new DataSet();
ds.ReadXml(path);
DataTable dt = ds.Tables[0];
And my output datatable is like.
I need to show my items on table. Is there any way to read properly ?
Try following xml linq which creates a separate row for each string :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Data;
namespace ConsoleApplication51
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("KEY", typeof(string));
dt.Columns.Add("RESULTING_ID", typeof(string));
dt.Columns.Add("TYPE", typeof(string));
XDocument doc = XDocument.Load(FILENAME);
XElement root = doc.Root;
XNamespace ns = root.GetDefaultNamespace();
foreach (XElement resultingString in doc.Descendants(ns + "Resultstring"))
{
string key = (string)resultingString.Element("Key");
string type = (string)resultingString.Element("Type");
string ids = string.Join(";", resultingString.Descendants("string").Select(x => (string)x));
dt.Rows.Add(new object[] { key, ids, type });
}
}
}
}
Code to put each string in a separate column
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Data;
namespace ConsoleApplication51
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XElement root = doc.Root;
XNamespace ns = root.GetDefaultNamespace();
int maxString = doc.Descendants(ns + "Resultstring").Select(x => x.Descendants("string").Count()).Max();
DataTable dt = new DataTable();
dt.Columns.Add("KEY", typeof(string));
dt.Columns.Add("TYPE", typeof(string));
for (int i = 0; i < maxString; i++)
{
dt.Columns.Add("RESULTING_ID_" + (i + 1).ToString(), typeof(string));
}
foreach (XElement resultingString in doc.Descendants(ns + "Resultstring"))
{
string key = (string)resultingString.Element("Key");
string type = (string)resultingString.Element("Type");
List<string> row = resultingString.Descendants("string").Select(x => (string)x).ToList();
row.Insert(0, key);
row.Insert(1, type);
dt.Rows.Add(row.ToArray());
}
}
}
}
With Cinchoo ETL - an open source library, you can easily convert Xml file to DataTable with few lines of code.
For your sample xml file, you can extract the data into datatable as below
using (var p = new ChoXmlReader(** YOUR XML FILE **)
.WithField("Key")
.WithField("Value", xPath: "/Values/string")
)
{
var dt = p.SelectMany(r => ((Array)r.Value).OfType<string>().Select(r1 => new { Key = r.Key, Value = r1})).AsDataTable();
}
Output:
Hope it helps.
your Resultstring xml node is repeating. Below code is working for me
<Resultstring>
<Key>Blablabla : </Key>
<Values>
<string>79,0441326460292</string>
<string>76,0959542079328</string>
<string>74,3061819154758</string>
<string>78,687039788779</string>
</Values>
<Type>list</Type>
<Key>Blablabla : </Key>
<Values>
<string>87,7110395931923</string>
</Values>
<Type>double</Type>
</Resultstring>
Dataset code
DataSet ds = new DataSet();
ds.ReadXml(path);
DataTable dtKey = ds.Tables[0];
DataTable dtValues = ds.Tables[1];
DataTable dtstring = ds.Tables[2];
DataTable dtType = ds.Tables[3];
My XML looks like this
<root>
<record>
<Object_Number> 1</Object_Number>
<Object_Level> 1</Object_Level>
<Object_Heading> Introduction</Object_Heading>
<Object_Text> </Object_Text>
<Milestones> </Milestones>
<Unique_ID> </Unique_ID>
<Field_type> Info</Field_type>
<SG_attribute> </SG_attribute>
<Object_Identifier>1</Object_Identifier>
<Object_URL>doors://D1DDBAPP04:36677/?version=2&prodID=0&view=0000001a&urn=urn:telelogic::1-432aa0956f684cff-O-1-00028f60</Object_URL>
</record>
...
records...
...
</root>
Is it possible bind a IEnumerable result to a DatgridView and automatic detect columns?
Initially, I've done this
ds = new DataSet();
ds.ReadXml(myXml);
Then, convert to a DataTable
dt = ds.Tables["record"]
And this can directly populate DGV
dgvDoors.DataSource = dt;
But now, I realize that it's more easily to manipulate data directly in XML (with LINQ) and need somehow to display that (filtered) results in DataGridView
IEnumerable<XElement> elements = xdoc.Element("root").Elements("record");
Now is it possible to display 'elements' to DataGridView and detect columns such in original XML?
Thank you,
PS.
var bs = new BindingSource { DataSource = elements};
dgvDoors.DataSource = bs;
This is not working correctly since instead of records, DGV will display some other columns such as
FirstAttribute
HasAttributes
HasElements
...
To make it working properly I would recommend converting your xml data to strongly typed View Models.
public class RecordViewModel
{
public string Number { get; set; }
public string Level { get; set; }
public string Heading { get; set; }
public string Milestones { get; set; }
}
Below implementation, please let know if it works as you expect:
var elements = xdoc.Element("root").Elements("record")
.Select(e => new RecordViewModel
{
Number = e.Element("Object_Number").Value,
Level = e.Element("Object_Level").Value,
Heading = e.Element("Object_Heading").Value,
Milestones = e.Element("Milestones").Value,
});
var bs = new BindingSource
{
DataSource = elements
};
dgvDoors.DataSource = bs;
The conversion between Xml Data and ViewModels above is not checking for nulls, so you can move the implementation to some mapper, where the logic of converting Xml data to ViewModel would be more complex.
Try following which matches your request
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication49
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
string[] columnNames = doc.Descendants("record").FirstOrDefault().Elements().Select(x => x.Name.LocalName).ToArray();
DataTable dt = new DataTable();
foreach (string col in columnNames)
{
dt.Columns.Add(col, typeof(string));
}
foreach (XElement record in doc.Descendants("record"))
{
DataRow newRow = dt.Rows.Add();
foreach (string columnName in columnNames)
{
newRow[columnName] = (string)record.Element(columnName);
}
}
}
}
}
Sample of XML File
<NvM_DataManager_Blocks
AlignmentConstraint="ManagedBy_DataManager"
GenerateBlockAccessAPI="Yes" UseProtectedSections="Yes" UseRteForDataManagerInterface="No">
<DATA_MANAGER_EEPROM_BLOCK Block_Crc_Type="NVM_CRC16"
Block_Priority="255" Block_Type="NVM_BLOCK_NATIVE"
ErrorCallback="" FeeOrEa_BlockId=""
Name="DataManager_Block_01"
Project_specific_information=""
Resistant_To_Changed_SW="No" Storage_In="Fee" Write_Only_At_WriteAll="No">
<DATA_ELEMENT CreateCommitedApi="Yes" DataSize=""
DataSize_bit="" Data_type="uint8" Default_Value="66"
Header_file="" Name="DataManager_DataElement_01"
Number_Of_Planned_Writes="255" VariantInit="No"/>
<DATA_ELEMENT CreateCommitedApi="Yes" DataSize=""
DataSize_bit="" Data_type="uint32"
Default_Value="255" Header_file=""
Name="DataManager_DataElement_02"
Number_Of_Planned_Writes="363" VariantInit="No"/>
</DATA_MANAGER_EEPROM_BLOCK>
This is my code.
//Load xml
XDocument xdoc = XDocument.Load("C:\\Users\\John\\Desktop\\Program\\file.xml");
var blocks2 = (from r in xdoc.Descendants("DATA_MANAGER_EEPROM_BLOCK")
select new
{
Name = r.Attribute("Name").Value,
//This line below does not the produce what is req. I need some help on how to fix this.
Sub_Elements = xdoc.Descendants("DATA_MANAGER_EEPROM_BLOCK").Descendants("DATA_ELEMENT")
}).ToList();
However, I have some issue to extract the sub elements : DataManager_DataElement_01 & DataManager_DataElement_02 and their attributes.
Try following
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("CrC_Type", typeof(string));
dt.Columns.Add("Priority", typeof(int));
dt.Columns.Add("Type", typeof(string));
dt.Columns.Add("Block_Name", typeof(string));
dt.Columns.Add("Data_Type", typeof(string));
dt.Columns.Add("Default_Value", typeof(int));
dt.Columns.Add("Element_Name", typeof(string));
dt.Columns.Add("Planned_Writes", typeof(int));
XDocument doc = XDocument.Load(FILENAME);
foreach (XElement block in doc.Descendants("DATA_MANAGER_EEPROM_BLOCK"))
{
string crcType = (string)block.Attribute("Block_Crc_Type");
int blockPriority = (int)block.Attribute("Block_Priority");
string blockType = (string)block.Attribute("Block_Type");
string blockName = (string)block.Attribute("Name");
foreach(XElement element in block.Elements("DATA_ELEMENT"))
{
string dataType = (string)element.Attribute("Data_type");
int defaultValue = (int)element.Attribute("Default_Value");
string elementName = (string)element.Attribute("Name");
int plannedWrites = (int)element.Attribute("Number_Of_Planned_Writes");
dt.Rows.Add(new object[] {
crcType,
blockPriority,
blockType,
blockName,
dataType,
defaultValue,
elementName,
plannedWrites
});
}
}
}
}
}
C# winform: I asked a similar Q but didn't reached to the solution so i want to make it more clear, I have a string let suppose
str = "<sample>
<sample1 name="val1">
<sample2 name="val2">
</sample2>
<sample2 name="val3">
<groupbox name="val4">
<field type="textArea" x="xxx" />
</groupbox>
</sample2>
</sample1>
<sample1 name="abc">
</sample1>
<sample1 name="xyz">
</sample1>
</sample>"
i want to get the attributes and thier values from this string and place it in gridView notice that this string is just an example it could be changed. or display in any control like richTextField .... etc
I've given this solution before - this code will parse your one XML string and it will return the list of attributes and their values - so what else / what more do you need??
private static List<KeyValuePair<string, string>> ParseForAttributeNames(string xmlContent)
{
List<KeyValuePair<string, string>> attributeNamesAndValues = new List<KeyValuePair<string, string>>();
XDocument xmlDoc = XDocument.Parse(xmlContent);
var nodeAttrs = xmlDoc.Descendants().Select(x => x.Attributes());
foreach (var attrs in nodeAttrs)
{
foreach (var attr in attrs)
{
string attributeName = attr.Name.LocalName;
string attributeValue = attr.Value;
attributeNamesAndValues.Add(new KeyValuePair<string, string>(attributeName, attributeValue));
}
}
return attributeNamesAndValues;
}
If you can explain in good, comprehensible English what else you need, I might make the effort to answer you once again with even more info.... but you need to be clear and precise about what it is you need - otherwise me as an illiterate idiot won't be able to answer......
try this:
StringReader rdr = new StringReader(str);
DataSet ds = new DataSet();
ds.ReadXml(str);
DataTable dt = ds.Tables[0];
datagridview.datasource = dt;
For your other question that keeps coming up over and over again (grabbing XML attributes from SQL Server) - this is a complete sample that will
read all rows from a table and extract all the XML columns
parse all the XML contents into a list of attribute name/values
return a bindable list of attribute name/value pairs, which you can bind to a ListView, a GridView - whatever you like.
Please check it out - and if it doesn't meet your needs, please explain in comprehensible English what it is that's still missing.....
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Xml.Linq;
namespace GrabAndParseXml
{
internal class AttrNameAndValue
{
public string AttrName { get; set; }
public string AttrValue { get; set; }
}
class Program
{
static void Main(string[] args)
{
// grab *ALL* the "XmlContent" columns from your database table
List<string> xmlContent = GrabXmlStringsFromDatabase();
// parse *ALL* your xml strings into a list of attribute name/values
List<AttrNameAndValue> attributeNamesAndValues = ParseForAttributeNamesAndValues(xmlContent);
// you can now easily bind this list of attribute names and values to a ListView, a GridView - whatever - try it!
}
private static List<string> GrabXmlStringsFromDatabase()
{
List<string> results = new List<string>();
// connection string - adapt to **YOUR SETUP** !
string connection = "server=(local);database=test;integrated security=SSPI";
// Query to get the XmlContent columns - I would **ALWAYS** recommend to have a WHERE clause
// to limit the number of rows returned from the query - up to you....
string query = "SELECT XmlContent FROM dbo.TestXml WHERE 1=1";
// set up connection and command for data retrieval
using(SqlConnection _con = new SqlConnection(connection))
using (SqlCommand _cmd = new SqlCommand(query, _con))
{
_con.Open();
// use a SqlDataReader to loop over the results
using(SqlDataReader rdr = _cmd.ExecuteReader())
{
while(rdr.Read())
{
// stick all XML strings into resulting list
results.Add(rdr.GetString(0));
}
rdr.Close();
}
_con.Close();
}
return results;
}
private static List<AttrNameAndValue> ParseForAttributeNamesAndValues(List<string> xmlContents)
{
// create resulting list of "AttrNameAndValue" objects
List<AttrNameAndValue> attributeNamesAndValues = new List<AttrNameAndValue>();
// loop over all XML strings retrieved from the database
foreach (string xmlContent in xmlContents)
{
// parse into an XDocument (Linq-to-XML)
XDocument xmlDoc = XDocument.Parse(xmlContent);
// find **ALL** attribute nodes
var nodeAttrs = xmlDoc.Descendants().Select(x => x.Attributes());
// loop over **ALL** atributes in each attribute node
foreach (var attrs in nodeAttrs)
{
foreach (var attr in attrs)
{
// stick name and value into the resulting list
attributeNamesAndValues.Add(new AttrNameAndValue { AttrName = attr.Name.LocalName, AttrValue = attr.Value });
}
}
}
return attributeNamesAndValues;
}
}
}