I am writing a prototype to programmatically get video data from a database and use C# to place this data into an XML manifest file. Each video is an asset element inside XML, and I am querying all the data I need from a SQLCommand.
Problem: The XML file can only hold up to 100 video assets per file, and so I need to come up with an iterator that saves 100 assets per file until I reach the end row in the database. I am using while(r.Read()), a SqlDataReader to go into the data base using a SqlCommand.
I would like to know how to go about this process of appending 100 assets per file using a certain SQLCommand and an iteration inside the reader to process all files needed.
Below is my code thus far! (Clearly I am going to have to change some things around, such as the global elements of the XML file, which need to go in every XML file created)
protected void btnExecute_Click(object sender, EventArgs e)
{
//On btn click, call method to execute program and save all files in local path
GetVideoData();
}
protected void GetVideoData()
{
string preparer = "AgencyOasis";
string type = "VIDEO_FULL";
XmlDocument doc = new XmlDocument();
XmlNode docNode = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
doc.AppendChild(docNode);
//add global elements:
//create parameters for each attribute in root to be replaced, and append the new root tag to empty XML doc
XmlElement root = doc.CreateElement("publisher-upload-manifest");
root.SetAttribute("publisher-id", tbPublisherID.Text);
root.SetAttribute("preparer", preparer);
doc.AppendChild(root);
//append notify as child to root, already in doc
if (!string.IsNullOrEmpty(tbEmail.Text)) {
XmlElement notify = doc.CreateElement("notify");
notify.SetAttribute("email", tbEmail.Text);
root.AppendChild(notify);
}
//THE REST OF THE ELEMENTS ARE A UNIQUE CASE FOR EACH VIDEO, THEREFORE SHOULD LOOP INSIDE THE QUERY RESULT SET, PER VIDEO.
string sql100 = "SELECT TOP 100 Location, VideoLibraryId, Title, Keywords, IsActive, Description FROM VideoLibrary";
const string _connStringName = "SanfordVideosConnectionString";
string dsn = ConfigurationManager.ConnectionStrings[_connStringName].ConnectionString;
using (SqlConnection conn = new SqlConnection(dsn))
using (SqlCommand cmd = new SqlCommand(sql100, conn))
{
conn.Open();
SqlDataReader r = cmd.ExecuteReader();
while (r.Read())
{
//while going through each row with above SQL command, set data to element attributes in doc for each asset
XmlElement asset = doc.CreateElement("asset");
asset.SetAttribute("filename", r["Location"].ToString());
asset.SetAttribute("refid", r["VideoLibraryId"].ToString());
// TODO: NEED ACTUAL FILE LOCATION BEFORE I CAN EXTRACT THE SIZE OF THE FILE ITSELF
/*create new FileInfo object to get length of existing video file
FileInfo f = new FileInfo(r["Location"].ToString());
long f1 = f.Length; */
//asset.SetAttribute("size", "10"); // TODO: f1.ToString() for static value of 2nd @
// TODO: NEED ACTUAL FILE LOCATION AGAIN FOR HASH-CODE
//asset.SetAttribute("hash-code", "10"); //TODO: GetMD5Hash(r["Location"].ToString())
//setting the type globally for all videos to VIDEO_FULL ensures FLV and MP4 formats
asset.SetAttribute("type", type);
root.AppendChild(asset);
XmlElement title = doc.CreateElement("title");
title.SetAttribute("name", r["Title"].ToString());
title.SetAttribute("refid", r["VideoLibraryId"].ToString());
title.SetAttribute("active", r["IsActive"].ToString().ToUpper());
// TODO: CHECK TO SEE IF VIDEO-FULL-REFID IS CORRECT
//title.SetAttribute("video-full-refid", r["Location"].ToString() + "-" + r["VideoLibraryId"].ToString());
XmlElement shortDesc = doc.CreateElement("short-description");
shortDesc.InnerText = GetTrimmedDescription(250, r["Description"].ToString());
title.AppendChild(shortDesc);
root.AppendChild(title);
XmlElement longDesc = doc.CreateElement("long-description");
longDesc.InnerText = GetTrimmedDescription(5000, r["Description"].ToString());
title.AppendChild(longDesc);
root.AppendChild(title);
}
}
//TEMPORARY FILE SAVE LOCATION TODO: SAVE MULTIPLE FILES IN LOCAL FOLDER
//returns the directory from where the current application domain was loaded
//string xmlPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, inputFileName1);
string xmlPath = Server.MapPath(txtBoxInput.Text);
XmlTextWriter writer = new XmlTextWriter(xmlPath, null);
writer.Formatting = Formatting.Indented;
doc.Save(xmlPath);
}
//Trims long and short descriptions to max size of chars depending on max size (250 for short and 5000 for long)
public string GetTrimmedDescription(int maxLength, string desc) {
if (desc.Length > maxLength)
{
return desc.Substring(0, (maxLength - 4)) + " ...";
}
else
{
return desc;
}
}
Feel free to ask me any questions about the program and I’ll try my best to explain!
If I keep your code mostly as is, here is a possible solution. I have added in some comments where I refactored pieces.
The general idea is to fetch everything (not just 100 records) and introduce a counter that tracks where you are at. Every 100 records you spit out the file and reset. After you’ve read everything you have to spit out what is remaining. Since there are multiple files created, you will also have to track that and use a different filename. I just added a file suffix. I think the code below should work for you.