Iterate through an XML document [closed] - c#

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 11 months ago.
Improve this question
What's the efficient way to iterate through this XML document using C#? This document is the result of relationship between two apps.
Hence there is the info for the user, and the info for the request itself.
Thank you in advance.
<?xml version="1.0" encoding="utf-16"?>
<Records count="2">
<Metadata>
<FieldDefinitions>
<FieldDefinition id="1001" name="Request ID" alias="Q_ID" />
<FieldDefinition id="1002" name="User" alias="Target" />
<FieldDefinition id="1003" name="Which item(s) is the access requested for?" alias="Which_items_is_requested" />
<FieldDefinition id="1004" name="Select specific(s) for item1" alias="item1" />
<FieldDefinition id="1005" name="Select specific(s) for item2" alias="item2" />
<FieldDefinition id="1006" name="Select specific(s) for item3" alias="item3" />
<FieldDefinition id="101" name="First Name" alias="First_Name" />
<FieldDefinition id="102" name="Last Name" alias="Last_Name" />
<FieldDefinition id="100" name="Email" alias="Email" />
</FieldDefinitions>
</Metadata>
<LevelCounts>
<LevelCount id="989" count="2" />
<LevelCount id="85" count="2" />
</LevelCounts>
<Record contentId="1092725" levelId="989" moduleId="564">
<Record contentId="736205" levelId="85" moduleId="84">
<Field id="100" type="1">john.smith#abc.com</Field>
<Field id="101" type="1">John</Field>
<Field id="102" type="1">Smith</Field>
</Record>
<Field id="1003" type="4">
<ListValues>
<ListValue id="11" displayName="Issues Management">item1</ListValue>
<ListValue id="13" displayName="Master Control Procedures">item3</ListValue>
</ListValues>
</Field>
<Field id="1001" type="6">123123</Field>
<Field id="1002" type="9">
<Reference id="736205">John Smith</Reference>
</Field>
<Field id="1005" type="9">
<Reference id="3">item11</Reference>
<Reference id="3">item12</Reference>
</Field>
<Field id="1006" type="9" />
<Field id="1004" type="9">
<Reference id="7">item31</Reference>
<Reference id="8">item32</Reference>
</Field>
</Record>
<Record contentId="1092759" levelId="989" moduleId="564">
<Record contentId="775678" levelId="85" moduleId="84">
<Field id="100" type="1">Peter.Smith#abc.com</Field>
<Field id="101" type="1">Peter</Field>
<Field id="102" type="1">Smith</Field>
</Record>
<Field id="1003" type="4">
<ListValues>
<ListValue id="11" displayName="Issues Management">item1</ListValue>
<ListValue id="12" displayName="Master Control Procedures">item2</ListValue>
<ListValue id="13" displayName="Control Procedure">item3</ListValue>
</ListValues>
</Field>
<Field id="1001" type="6">123124</Field>
<Field id="1002" type="9">
<Reference id="775678">Peter Smith</Reference>
</Field>
<Field id="1005" type="9">
<Reference id="3">item11</Reference>
<Reference id="4">item12</Reference>
</Field>
<Field id="1006" type="9">
<Reference id="5">item21</Reference>
<Reference id="6">item22</Reference>
</Field>
<Field id="1004" type="9">
<Reference id="7">item31</Reference>
<Reference id="8">item32</Reference>
</Field>
</Record>
</Records>
What's the efficient way to iterate through this XML document using C#? This document is the result of relationship between two apps.
Hence there is the info for the user, and the info for the request itself.
Thank you in advance.

From the comments, your question is how you deserialize the nested records.
A class structure like this seems to work:
public class Records
{
[XmlElement("Record")]
public List<Record> Items { get; } = new();
}
public class Record
{
[XmlAttribute("contentId")]
public int ContentId { get; set; }
[XmlElement("Record")]
public Record ChildRecord { get; set; }
[XmlElement("Field")]
public List<Field> Fields { get; } = new();
}
public class Field
{
[XmlAttribute("id")]
public int Id { get; set; }
[XmlElement("Reference")]
public List<Reference> References { get; } = new();
[XmlArray("ListValues")]
public List<ListValue> ListValues { get; } = new();
[XmlText]
public string Content { get; set; }
}
public class Reference
{
[XmlAttribute("id")]
public int Id { get; set; }
}
public class ListValue
{
[XmlAttribute("id")]
public int Id { get; set; }
[XmlText]
public string Content { get; set; }
}
See this doc on how to use the various attributes.
I haven't bothered to deserialize all of the attributes, or the Metadata or LevelCounts sections -- those are an exercise for the reader!
Use an XmlSerializer, for example:
using var reader = new StringReader(input);
var records = (Records)new XmlSerializer(typeof(Records)).Deserialize(reader);
See it on dotnetfiddle.net.

To flatten data into one table is messy but can be done. See below
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using System.Data;
namespace ConsoleApplication21
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
StreamReader sReader = new StreamReader(FILENAME);
//skip 1st line containing UTF-16
sReader.ReadLine();
XDocument doc = XDocument.Load(sReader);
DataTable dt = new DataTable();
dt.Columns.Add("Field Id", typeof(int));
dt.Columns.Add("Field Name", typeof(string));
dt.Columns.Add("Alias", typeof(string));
dt.Columns.Add("Main Content ID", typeof(int));
dt.Columns.Add("Main Level ID", typeof(int));
dt.Columns.Add("Main Module ID", typeof(int));
dt.Columns.Add("Sub Content ID", typeof(int));
dt.Columns.Add("Sub Level ID", typeof(int));
dt.Columns.Add("Sub Module ID", typeof(int));
dt.Columns.Add("Type", typeof(int));
dt.Columns.Add("Field Value Name", typeof(string));
dt.Columns.Add("Field Text", typeof(string));
dt.Columns.Add("List Value Id", typeof(int));
dt.Columns.Add("Display Name", typeof(string));
dt.Columns.Add("List Value Text", typeof(string));
dt.Columns.Add("Reference Id", typeof(int));
dt.Columns.Add("Reference Text", typeof(string));
foreach (XElement fieldDefinition in doc.Descendants("FieldDefinition"))
{
DataRow newRow = dt.Rows.Add();
newRow["Field Id"] = (int)fieldDefinition.Attribute("id");
newRow["Field Name"] = (string)fieldDefinition.Attribute("name");
newRow["Alias"] = (string)fieldDefinition.Attribute("alias");
}
foreach (XElement record in doc.Root.Elements("Record"))
{
int mainContentId = (int)record.Attribute("contentId");
int mainLevelId = (int)record.Attribute("levelId");
int mainModuleId = (int)record.Attribute("moduleId");
foreach(XElement subRecord in record.Elements("Record"))
{
int subContentId = (int)record.Attribute("contentId");
int subLevelId = (int)record.Attribute("levelId");
int subModuleId = (int)record.Attribute("moduleId");
foreach (XElement field in subRecord.Elements("Field"))
{
int fieldId = (int)field.Attribute("id");
int fieldType = (int)field.Attribute("type");
string fieldName = (string)field;
DataRow fieldRow = dt.AsEnumerable().Where(x => x.Field<int>("Field Id") == fieldId).First();
fieldRow["Main Content ID"] = mainContentId;
fieldRow["Main Level ID"] = mainLevelId;
fieldRow["Main Module ID"] = mainModuleId;
fieldRow["Sub Content ID"] = subContentId;
fieldRow["Sub Level ID"] = subLevelId;
fieldRow["Sub Module ID"] = subModuleId;
fieldRow["Type"] = fieldType;
fieldRow["Field Value Name"] = fieldName;
}
foreach (XElement field in record.Elements("Field"))
{
int fieldId = (int)field.Attribute("id");
int fieldType = (int)field.Attribute("type");
string fieldText = (string)field;
int count = 0;
DataRow fieldRow = dt.AsEnumerable().Where(x => x.Field<int>("Field Id") == fieldId).First();
List<XElement> listValues = field.Descendants("ListValue").ToList();
List<XElement> references = field.Elements("Reference").ToList();
if (listValues.Count > 0)
{
foreach (XElement listValue in listValues)
{
count++;
int listValueId = (int)listValue.Attribute("id");
string displayName = (string)listValue.Attribute("displayName");
string listValueText = (string)listValue;
if (count > 1)
{
string fieldName = fieldRow.Field<string>("Field Name");
string alias = fieldRow.Field<string>("Alias");
fieldRow = dt.Rows.Add();
fieldRow["Field Id"] = fieldId;
fieldRow["Field Name"] = fieldName;
fieldRow["Alias"] = alias;
}
fieldRow["Main Content ID"] = mainContentId;
fieldRow["Main Level ID"] = mainLevelId;
fieldRow["Main Module ID"] = mainModuleId;
fieldRow["Type"] = fieldType;
if(fieldText.Length > 0) fieldRow["Field Text"] = fieldText;
fieldRow["List Value Id"] = listValueId;
fieldRow["Display Name"] = displayName;
fieldRow["List Value Text"] = listValueText;
}
}
count = 0;
if (references.Count > 0)
{
foreach (XElement reference in references)
{
count++;
int referenceId = (int)reference.Attribute("id");
string referenceText = (string)reference;
if (count > 1)
{
string fieldName = fieldRow.Field<string>("Field Name");
string alias = fieldRow.Field<string>("Alias");
fieldRow = dt.Rows.Add();
fieldRow["Field Id"] = fieldId;
fieldRow["Field Name"] = fieldName;
fieldRow["Alias"] = alias;
}
fieldRow["Main Content ID"] = mainContentId;
fieldRow["Main Level ID"] = mainLevelId;
fieldRow["Main Module ID"] = mainModuleId;
fieldRow["Type"] = fieldType;
if (fieldText.Length > 0) fieldRow["Field Text"] = fieldText;
fieldRow["Reference Id"] = referenceId;
fieldRow["Reference Text"] = referenceText;
}
}
if((listValues.Count == 0) && (references.Count == 0))
{
fieldRow["Type"] = fieldType;
if (fieldText.Length > 0) fieldRow["Field Text"] = fieldText;
}
}
}
}
dt = dt.AsEnumerable().OrderBy(x => x.Field<int>("Field Id")).CopyToDataTable();
}
}
}

Related

Filter XML collection based on child node data in c#

I have following XML collection of students as shown below.
<stdXmlFormat version="1.0">
<students>
<field id="ClassId">CB0012</field>
<field id="ClassName">CBSE-12</field>
<student id="123">
<field id="SFirstNm">Ram</field>
<field id="SLastNm">Raju</field>
<field id="RollNumber">001</field>
</student>
<student id="124">
<field id="SFirstNm">Sita</field>
<field id="SLastNm">M</field>
<field id="RollNumber">002</field>
</student>
<collection id="StudentCollection">
<record>
<field id="StudentId">5094e0ef-c966-484d-9892-e62bd828e7cf</field>
<field id="FirstName">Ram</field>
<field id="LastName">Raju</field>
</record>
<record>
<field id="StudentId">70a0350a-9556-46f6-b089-bebcc278b1c1</field>
<field id="FirstName">Sita</field>
<field id="LastName">M</field>
</record>
</collection>
<collection id="AccountTransactions">
<record>
<field id="Id">62f4181a-5510-4522-a24a-7d3005f2a907</field>
<field id="TransactionType">Fees</field>
<field id="Balance">5000.00</field>
</record>
<record>
<field id="Id">0958d991-c777-46b3-954c-3682ff735bfc</field>
<field id="TransactionType">Fine</field>
<field id="Balance">2000.00</field>
</record>
<record>
<field id="Id">3aadb37d-d066-491f-8525-2e299ad8d88b</field>
<field id="TransactionType">Fees</field>
<field id="Balance">6000.00</field>
</record>
</collection>
<collection id="StudentAccountTransactions">
<record>
<field id="Id">5e7d0c97-8759-4beb-a688-009e23f10590</field>
<field id="StudentId">5094e0ef-c966-484d-9892-e62bd828e7cf</field>
<field id="AccountTransactionsId">62f4181a-5510-4522-a24a-7d3005f2a907</field>
</record>
<record>
<field id="Id">b22bf993-4dc2-49e6-879f-504ca4ec8424</field>
<field id="StudentId">5094e0ef-c966-484d-9892-e62bd828e7cf</field>
<field id="AccountTransactionsId">0958d991-c777-46b3-954c-3682ff735bfc</field>
</record>
<record>
<field id="Id">44641d91-38bf-4e24-895c-20f92f390acf</field>
<field id="StudentId">70a0350a-9556-46f6-b089-bebcc278b1c1</field>
<field id="AccountTransactionsId">3aadb37d-d066-491f-8525-2e299ad8d88b</field>
</record>
</collection>
</students>
</stdXmlFormat>
The students node is the parent node which consists of child nodes as and collections (StudentCollection, AccountTransactions and StudentAccountTransactions).
<stdXmlFormat version="1.0">
<students>
<student></student>
<collection id="StudentCollection"/>
<collection id="AccountTransactions"/>
<collection id="StudentAccountTransactions"/>
</students>
</stdXmlFormat>
students node is containing all the student details such first name,last name, roll number etc(this was an old collection with more information.some attributes i have removed for better reading and understanding)
And same information is available in the new collection StudentCollection but with less data.this collection is having StudentId (a unique guid used for identifying the student in other collections). the only relation with students and StudentCollection is the student first name and last name.
The AccountTransactions is the collection which holds id (a unique guid for identifying each transactions) and other transaction details. The id in this collection used as AccountTransactionsId in the StudentAccountTransactions collection.
The final collection StudentAccountTransactions which holds the studentid (from StudentCollection) and AccountTransactionsId (from AccountTransactions collection).
So from this list i need to get the details of the students and pass it to DB TEAM for saving to database.They are ready with table structure as shown below
Basically i need to fetch the SFirstNm,SLastNm,RollNumber( from student), StudentId,AccountTransactionsId and StudentAccountTransactionsId from this collection.
I have tried to get the data using XMLdocument and Xdocument but nothing worked
string xpath = #"/stdXmlFormat/students/students/field";
XmlNodeList nodeListstudent = root.SelectNodes(xpath);
foreach (XmlNode item in nodeListstudent )
{
string SID = item.Attributes["id"].Value;
string sFirstNm, sLastNm = string.Empty;
foreach (XmlNode childNodes in item .ChildNodes)
{
string NodeName = childNodes.Attributes["id"].Value;
string NodeValue = childNodes.InnerText;
if (NodeName == "sFirstNm")
{
sFirstNm= NodeValue;
}
if (NodeName == "aBLastNm")
{
sLastNm = NodeValue;
}
}
}
From this i was able to get the student first name and last names etc but how i can fetch the student id from StudentCollection using first name and last name? i am really stuck here please help. with that studentid i need to get other details such as AccountTransactionsId and StudentAccountTransactionsId.
I tried to filter the studentid collections using following way for testing purpose but not worked.
XmlNodeList nodes = jsonXmlDocument.SelectNodes("//stdXmlFormat/students/collection/record/field[#id='5094e0ef-c966-484d-9892-e62bd828e7cf']");
Please help me !
Here is a start :
using System;
using System.Linq;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApp2
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
DataTable dt = new DataTable();
dt.Columns.Add("StudentId", typeof(string));
dt.Columns.Add("SFirstNm", typeof(string));
dt.Columns.Add("SLastNm", typeof(string));
dt.Columns.Add("RollNumber", typeof(string));
dt.Columns.Add("AccountTransaction", typeof(string));
dt.Columns.Add("StudentAccountTransaction", typeof(string));
XDocument doc = XDocument.Load(FILENAME);
XElement xStudents = doc.Descendants("students").FirstOrDefault();
var students = xStudents.Elements("student")
.Select(x => new
{
id = (string)x.Attribute("id"),
sFName = (string)x.Elements("field").Where(y => (string)y.Attribute("id") == "SFirstNm").FirstOrDefault(),
sLName = (string)x.Elements("field").Where(y => (string)y.Attribute("id") == "SLastNm").FirstOrDefault(),
rollNumber = (string)x.Elements("field").Where(y => (string)y.Attribute("id") == "RollNumber").FirstOrDefault(),
}).ToList();
XElement xStudentCollection = doc.Descendants("collection").Where(x => (string)x.Attribute("id") == "StudentCollection").FirstOrDefault();
var studentCollection = xStudentCollection.Elements("record")
.Select(x => new
{
sId = (string)x.Elements("field").Where(y => (string)y.Attribute("id") == "StudentId").FirstOrDefault(),
sFName = (string)x.Elements("field").Where(y => (string)y.Attribute("id") == "FirstName").FirstOrDefault(),
sLName = (string)x.Elements("field").Where(y => (string)y.Attribute("id") == "LastName").FirstOrDefault(),
}).ToList();
XElement xAccountTransactions = doc.Descendants("collection").Where(x => (string)x.Attribute("id") == "AccountTransactions").FirstOrDefault();
var accountTransactions = xAccountTransactions.Elements("record")
.Select(x => new
{
tId = (string)x.Elements("field").Where(y => (string)y.Attribute("id") == "Id").FirstOrDefault(),
type = (string)x.Elements("field").Where(y => (string)y.Attribute("id") == "TransactionType").FirstOrDefault(),
balanse = (decimal)x.Elements("field").Where(y => (string)y.Attribute("id") == "Balance").FirstOrDefault(),
}).ToList();
XElement xStudentAccountTransactions = doc.Descendants("collection").Where(x => (string)x.Attribute("id") == "StudentAccountTransactions").FirstOrDefault();
var studentAccountTransactions = xStudentAccountTransactions.Elements("record")
.Select(x => new
{
satId = (string)x.Elements("field").Where(y => (string)y.Attribute("id") == "Id").FirstOrDefault(),
sId = (string)x.Elements("field").Where(y => (string)y.Attribute("id") == "StudentId").FirstOrDefault(),
tId = (string)x.Elements("field").Where(y => (string)y.Attribute("id") == "AccountTransactionsId").FirstOrDefault(),
}).ToList();
var studentRoll = students.Select(s => studentCollection.Where(sc => (s.sFName == sc.sFName) && (s.sLName == sc.sLName))
.Select(x => new { fName = s.sFName, lName = s.sLName, roll = s.rollNumber, sId = x.sId }).FirstOrDefault()).ToList();
var tranactions = accountTransactions.Select(at => studentAccountTransactions.Where(act => at.tId == act.tId)
.Select(x => new { tId = x.tId, type = at.type, balance = at.balanse, satId = x.satId }).FirstOrDefault()).ToList();
var results = (from sat in studentAccountTransactions
join tr in tranactions on sat.tId equals tr.tId
join sr in studentRoll on sat.sId equals sr.sId
select new { sr = sr, tr = tr, sat = sat })
.ToList();
foreach(var r in results)
{
dt.Rows.Add(new object[]
{
r.sr.sId,
r.sr.fName,
r.sr.lName,
r.sr.roll,
r.tr.tId,
r.sat.satId
});
}
}
}
}

Read XML with C# and fill List<T>

I have an XML document that contains data about two table.
The structure is like this
<doc>
<table name="ordini">
<row>
<field name="id">0431524493258932</field>
<field name="anno">2018</field>
<field name="att">0000</field>
<field name="cen">01</field>
...
</row>
<row>
<field name="id">1041524493596749</field>
<field name="anno">2018</field>
<field name="att">0000</field>
<field name="cen">01</field>
...
</row>
...
</table>
<table name="righe">
<row>
<field name="id">0431524493258932</field>
<field name="anno">2018</field>
<field name="att">0000</field>
<field name="cen">4U</field>
....
</table>
<doc>
I am trying this way with first table in XML with a lot of confusion
var doc = XDocument.Load(filename);
var ordcli = doc.Descendants("table")
.Where(i => (string)i.Attribute("name") == "ordini")
.Descendants("row")
.Select(e => e.Elements());
foreach (var item in ordcli)
{
foreach (var i in item)
{
Console.WriteLine(i);
}
}
How can I read every row element and get field name to instantiate my Order class and OrderDetails class?
When I have my List<Order> and List<OrderDetails> filled I can populate relative tables.
I hope I've explained my requirement well.
I've never used XlmReader or Linq2Xml. It's first time.
try following code :
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)
{
new XML_DataSet(FILENAME);
}
}
public class XML_DataSet
{
static DataSet ds = new DataSet();
public XML_DataSet(string filename)
{
XDocument doc = XDocument.Load(filename);
foreach(XElement table in doc.Descendants("table"))
{
ds.Tables.Add(ReadTable(table));
}
}
private DataTable ReadTable(XElement table)
{
DataTable dt = new DataTable();
Boolean first = true;
foreach (XElement xRow in table.Elements("row"))
{
if (first)
{
foreach (XElement field in xRow.Elements("field"))
{
dt.Columns.Add((string)field.Attribute("name"), typeof(string));
}
first = false;
}
DataRow newRow = dt.Rows.Add();
foreach (XElement field in xRow.Elements("field"))
{
newRow[(string)field.Attribute("name")] = (string)field;
}
}
return dt;
}
}
}

How to make this xml query shorter

I spent 3 days to read this xml file and put the details in to the database. It works the way it should be but I know the way i read this xml file is not the proper way.
If the xml file is bigger than 2mb. (which contains about 1000 records), it takes more than 1 minute to load.
Can you please show me how to make this query shorter.
this is the xml
<?xml version="1.0" encoding="UTF-8"?>
<outputTree xmlns="http://www.ibm.com/software/analytics/spss/xml/oms" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.ibm.com/software/analytics/spss/xml/oms http://www.ibm.com/software/analytics/spss/xml/oms/spss-output-1.8.xsd">
<command command="Summarize" displayOutlineValues="label" displayOutlineVariables="label" displayTableValues="label" displayTableVariables="label" lang="en" text="Summarize">
<pivotTable subType="Report" text="Batch">
<dimension axis="row" text="Cases">
<group label="Test Site" text="Test Site" varName="PLANT_DESC" variable="true">
<group hide="true" text="A">
<group string="A" text="A" varName="PLANT_DESC">
<group label="Product" text="Product" varName="PROD_DESC" variable="true">
<group hide="true" text="A">
<group string="S" text="S" varName="PROD_DESC">
<group label="Batch Number" text="Batch Number" varName="BATCH_NO" variable="true">
<group hide="true" text="A">
<group number="3704542" text="3704542" varName="BATCH_NO">
<category number="1" text="1">
<dimension axis="column" text="Variables">
<category label="Batch Run" text="Batch Run" varName="BATCH_RUN_ID" variable="true">
<cell number="4202" text="4202" varName="BATCH_RUN_ID"/>
</category>
<category label="Application" text="Application" varName="APP_ID" variable="true">
<cell label="Calibration" number="101" text="Calibration" varName="APP_ID"/>
</category>
<category label="Date Tested" text="Date Tested" varName="TEST_DATE" variable="true">
<cell date="2014-09-23T10:53:19" format="date" text="23-SEP-2014" varName="TEST_DATE"/>
</category>
</dimension>
</category>
</group>
</group>
</group>
</group>
</group>
</group>
</group>
</group>
</group>
</dimension>
</pivotTable>
</command>
</outputTree>
This is the c#
XElement root = XElement.Load(Page.Server.MapPath(#"oril.xml"));
XNamespace ad = "http://www.ibm.com/software/analytics/spss/xml/oms";
var cats = from cat in root.Descendants(ad + "dimension").Where
(cat => (string)cat.Attribute("axis") == "column" && (string)cat.Attribute("text") == "Variables")
select new
{
BATCH_NO = cat.Parent.Parent.Attribute("number").Value,
RUN_NO = cat.Parent.Attribute("number").Value,
//// 1
BATCH_RUN_ID = cat.Descendants(ad + "category").Elements(ad + "cell")
.Where(a => (string)a.Attribute("varName") == "BATCH_RUN_ID")
.Select(c => c.Attribute("number").Value),
//// 2
APP_ID = cat.Descendants(ad + "category").Elements(ad + "cell")
.Where(a => (string)a.Attribute("varName") == "APP_ID")
.Select(c => c.Attribute("label").Value),
//// 3
TEST_DATE = cat.Descendants(ad + "category").Elements(ad + "cell")
.Where(a => (string)a.Attribute("varName") == "TEST_DATE")
.Select(c => c.Attribute("date").Value),
////
//// Another 12
////
};
foreach (var cat in cats)
{
foreach (string s in cat.BATCH_RUN_ID)
{
xmlTitle.Text += "BATCH_NO: " + cat.BATCH_NO + " </br>";
xmlTitle.Text += "RUN_NO: " + cat.RUN_NO + " </br>";
xmlTitle.Text += "BATCH_RUN_ID: " + s + " </br>";
}
foreach (string s in cat.APP_ID)
{
xmlTitle.Text += "APP_ID: " + s + " </br>";
i_APP_ID = s;
}
foreach (string s in cat.TEST_DATE)
{
xmlTitle.Text += "TEST_DATE: " + s + " </br>";
i_TEST_DATE = s;
}
foreach (string s in cat.CB_USED)
{
xmlTitle.Text += "CB_USED: " + s + " </br>";
i_CB_USED = s;
}
////
//// Another 12
////
}
You could use Objects, since this is an Object Oriented Language, to ease some of your .Descendants().Elements() pain.
public class Category
{
public readonly XElement self;
public readonly XNamespace ns;
public Category(XNamespace xn, XElement cat) { self = cat; ns = xn; }
public string Name { get { return (string)self.Attribute("varName"); } }
public Cell Cell { get { return _Cell ?? (_Cell = new Cell(self.Elements(ns+"cell").First())); } }
Cell _Cell;
}
public class Cell
{
public readonly XElement self;
public Cell(XElement cell) { self = cell; }
public string Name { get { return (string)self.Attribute("varName"); } }
public string Number { get { return (string)self.Attribute("number"); } }
public string Date { get { return (string)self.Attribute("date"); } }
public string Label { get { return (string)self.Attribute("label"); } }
}
public class Dimension
{
public readonly XElement self;
public readonly XNamespace ns;
public Dimension(XNamespace xn, XElement dim) { self = dim; ns = xn; }
public string Axis { get { return (string)self.Attribute("axis"); } }
public string Text { get { return (string)self.Attribute("text"); } }
public string BatchNo { get { return self.Parent.Parent.Attribute("number").Value } }
public string RunNo { get { return self.Parent.Attribute("number").Value } }
public Category[] Categories
{ get { return _Categories ?? (_Categories = self.Elements(ns + "category")
.Select(cat => new Category(ns, cat))
.ToArray()); }
}
Category[] _Categories;
}
Then to use your root and ad defined in your post. If nothing else, it is more readable,
but it should be faster since once a Cell is created in a Category, it doesn't need to find it
on every cell call. And likewise with each category in a dimension.
var dims = root.Descendants(ad + "dimension")
.Select(dim => new Dimension(ad, dim))
.Where(Dim => Dim.Axis == "column" && Dim.Text == "Variables");
var cats = dims.Select(dim => new
{
BATCH_NO = dim.BatchNo,
RUN_NO = dim.RunNo,
//// 1
BATCH_RUN_ID = dim.Categories
.Where(cat => cat.Name == "BATCH_RUN_ID")
.Select(cat => cat.Cell.Number),
//// 2
APP_ID = dim.Categories
.Where(cat => cat.Name == "APP_ID")
.Select(cat => cat.Cell.Label),
//// etc
}
ps I typed this manually, it may not directly compile as is, but it would be something simple like a missing ;
First thing first,
when you need to concat alot of loop String like that you need to use StringBuilder to help it first
example:
StringBuilder sb = new StringBuilder();
foreach (var cat in cats)
{
foreach (string s in cat.BATCH_RUN_ID)
{
//xmlTitle.Text += "BATCH_NO: " + cat.BATCH_NO + " </br>";
sb.append("BATCH_NO: ");
sb.append( cat.BATCH_NO );
sb.append(" </br>");
// more and more, without using String + String
}
}
//at the end of the loop, just put it back to xml text
xmlTitle.Text = sb.toString();

Highlighting in SolrNet

I have a problem to get highlighting working. I use a ASP.Net MVC Application with a WCF Service. The WCF Service return the results to the view. My code is:
public IEnumerable<Dictionary<string, string>> SolrQuery(string searchString)
{
SolrInitialSetup();
var solr = ServiceLocator.Current.GetInstance<ISolrOperations<SolrPDFDocument>>();
var results = solr.Query(new SolrQueryByField("author", searchString),
new QueryOptions
{
Highlight = new HighlightingParameters
{
Fields = new[] { "search_snippet" },
}
});
var returnedResults = new List<Dictionary<string, string>>();
if (results.Count > 0)
{
foreach (var pdfDoc in results)
{
var docBuffer = new Dictionary<string, string>();
docBuffer.Add("Id", ""+pdfDoc.Id.GetHashCode());
docBuffer.Add("Content", "" + pdfDoc.Content.ElementAt(0));
docBuffer.Add("Version", "" + pdfDoc.Version);
foreach (var h in results.Highlights[results[0].Id])
{
docBuffer.Add("search_snippet", String.Format("{0}", string.Join(", ", h.Value.ToArray())));
Debug.WriteLine("search_snippet", String.Format("{0}", string.Join(", ", h.Value.ToArray())));
}
returnedResults.Add(docBuffer);
}
}
return returnedResults;
}
# Line foreach (var h in results.Highlights[results[0].Id]) I get an error in the browser The given key was not present in the dictionary. I have no idea whats wrong.
My schema.xml:
<field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
<field name="content" type="text_general" indexed="true" stored="true" multiValued="true" termVectors="true" termPositions="true" termOffsets="true"/>
<field name="author" type="text_general" indexed="true" stored="true" termVectors="true" termPositions="true" termOffsets="true"/>
<field name="_version_" type="long" indexed="true" stored="true"/>
<field name="search_snippet" type="text_general" indexed="true" stored="true" termVectors="true" termPositions="true" termOffsets="true" />
My SolrPDFDocument.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SolrNet.Attributes;
namespace WcfSearchService
{
class SolrPDFDocument
{
[SolrUniqueKey("id")]
public string Id { get; set; }
[SolrField("author")]
public string Author { get; set; }
[SolrField("content")]
public ICollection<string> Content { get; set; }
[SolrField("search_snippet")]
public ICollection<string> SearchSnippet { get; set; }
[SolrField("_version_")]
public long Version { get; set; }
}
}
My solrconfig.xml
<requestHandler name="/select" class="solr.SearchHandler">
<!-- default values for query parameters can be specified, these
will be overridden by parameters in the request
-->
<lst name="defaults">
<str name="echoParams">explicit</str>
<int name="rows">10</int>
<str name="df">text</str>
<!-- Highlighting defaults -->
<str name="hl">on</str>
<str name="hl.fl">search_snippet author content</str>
</lst>
</requestHandler>
OK i have solved my problem.
Instead of using the sample code like that:
var results = solr.Query(new SolrQueryByField("author", searchString),
new QueryOptions
{
Highlight = new HighlightingParameters
{
Fields = new[] { "author" },
}
});
I set the Parameter of the new Fields like this:
var results = solr.Query(new SolrQueryByField("text", searchString),
new QueryOptions
{
Highlight = new HighlightingParameters
{
Fields = new[] { "*" },
}
});
So I'm getting all the snippets to all results. Thanks for your help!!!!
You might not be getting any highlight results at all. Can you debug your code and validate that results.Highlights is populated. Also check your highlighting defaults settings as I believe you need to set hl=true not on.
<str name="hl">true</str>
This is interesting. For me, this wasn't working (I wasn't getting any results):
var results = solr.Query(new SolrQueryByField("text", searchString),
new QueryOptions
{
Highlight = new HighlightingParameters
{
Fields = new[] { "*" },
}
});
But, this works for me:
var results = solr.Query(string.Format("{0}:{1}", "text", searchString),
new QueryOptions
{
Highlight = new HighlightingParameters
{
Fields = new[] { "*" },
}
});
I am using solr 4.6.0 and SolrNet build #173 (16 Oct 13 00:32)

xml output from asp.net webservice

I want to see below format as output of my webservice but it is return empty, would you mind help me to how figure it out?
I am using asp.net2
I would like to receive out put like below:
<LIST OF CUSTOMER>
<CustomerData>
<V_CUST_CODE value="c1"/>
<V_CUST_NAME value="Customer 1"/>
</CustomerData>
<CustomerData>
<V_CUST_CODE value="c2"/>
<V_CUST_NAME value="Customer 2"/>
</CustomerData>
<CustomerData>
<V_CUST_CODE value="c2"/>
<V_CUST_NAME value="Customer 2"/>
</CustomerData>
<LIST OF CUSTOMER/>
my current out put:
<?xml version="1.0" encoding="utf-8" ?>
<ArrayOfCustomerData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://123.23.45.34/sms/" />
my webservice
[WebMethod]
public List<CustomerData> getFMSCustomerName()
{
string[] cols = {"V_CUST_CODE", "V_CUST_NAME"};
ArrayList CustomerList = (ArrayList)db.Select(cols, "table1", "", "order by V_CUST_NAME");
List<CustomerData> cd = new List<CustomerData>();
foreach(DataRow dr in CustomerList)
cd.Add(new CustomerData(dr["V_CUST_CODE"].ToString(), dr["V_CUST_NAME"].ToString()));
return cd;
}
public class CustomerData
{
private string _V_CUST_CODE;
private string _V_CUST_NAME;
public String V_CUST_CODE
{
get
{
return this._V_CUST_CODE;
}
set
{
this._V_CUST_CODE = value;
}
}
public String V_CUST_NAME
{
get
{
return this._V_CUST_NAME;
}
set
{
this._V_CUST_NAME = value;
}
}
public CustomerData(String V_CUST_CODE, String V_CUST_NAME)
{
this.V_CUST_CODE = V_CUST_CODE;
this.V_CUST_NAME = V_CUST_NAME;
}
public CustomerData() { }
}
I solve my problem by using below code:
public String getFMSCustomerName()
{
string[] cols = {"V_CUST_CODE", "V_CUST_NAME"};
ArrayList CustomerList = (ArrayList)db.Select(cols, "table1", " V_STATUS = 'A'", "order by V_CUST_NAME");
//List<CustomerData> cd = new List<CustomerData>();
XmlDocument doc = new XmlDocument();
XmlNode CustomersNode = doc.CreateElement("Customers");
doc.AppendChild(CustomersNode);
foreach (DataRow dr in CustomerList)
{
// cd.Add(new CustomerData(dr["V_CUST_CODE"].ToString(), dr["V_CUST_NAME"].ToString()));
XmlNode customerNode = doc.CreateElement("Customer");
XmlNode V_CUST_CODENode = doc.CreateElement("V_CUST_CODE");
V_CUST_CODENode.AppendChild(doc.CreateTextNode(dr["V_CUST_CODE"].ToString()));
customerNode.AppendChild(V_CUST_CODENode);
XmlNode V_CUST_NAMENode = doc.CreateElement("V_CUST_NAME");
V_CUST_NAMENode.AppendChild(doc.CreateTextNode(dr["V_CUST_NAME"].ToString()));
customerNode.AppendChild(V_CUST_NAMENode);
CustomersNode.AppendChild(customerNode);
}
return doc.OuterXml;
}

Categories

Resources