Firefox Bookmark Manager by C# and XML






4.47/5 (27 votes)
With KingMark you can exchange your bookmarks between Firefox and IE


Introduction
This is a simple Firefox bookmark manager. With KingMark you can import, manage and export Firefox bookmarks as a HTML or *.url or XML file. KingMark works with XML, first converts the Firefox bookmark file into the XML file and then converts it into the HTML file.
Using the Code
Creating XML file
KingMark creates an XML file with unique names for each node. For example, this is a node in the XML file:
<NODE9 NAME="FireFox" ADD_DATE="1213909970"
LAST_MODIFIED="1220234375" DESC="">
<BOOKMARK10 NAME="Mozilla - Home"
HREF="http://en-us.www.mozilla.com/en-US/"
SHORTCUTURL="mozila" DESC=""
ADD_DATE="1183006386" LAST_MODIFIED="1220234476"
ICON_URI="" ICON="" />
<BOOKMARK11 NAME="mozillaZine Forums"
HREF="http://forums.mozillazine.org/index.php"
SHORTCUTURL="" DESC="" ADD_DATE="1214351419" LAST_MODIFIED="1220233809"
ICON_URI="" ICON="" />
<BOOKMARK12 NAME="Mozilla Support"
HREF="http://support.mozilla.com/tiki-my_tiki.php#content_forum"
SHORTCUTURL="" DESC="" ADD_DATE="1214143305" LAST_MODIFIED="1220233808"
ICON_URI="" ICON="" />
<BOOKMARK13 NAME="AfzoneHaye FF"
HREF="http://addons.mozillafirefox.ir/" SHORTCUTURL=""
DESC="" ADD_DATE="1218070432" LAST_MODIFIED="1219953174"
ICON_URI="" ICON="" />
</NODE9>
As you can see, each node has a unique name so I used these names for denominating TreeView nodes' names. Well by this denomination we can find each node in an XML file and TreeView control easily.
I saved the biggest node number (for example : <BOOKMARK13 ... />) in an attribute (ELEMENTS
) in the root node. With this attribute we can find the latest number used in denomination and we start denominating after it. And with OPTIMIZE XML FILE, KingMark arranges the XML elements .
First: KingMark converts the FF BookMark file (HTML file) to the List<string>
object (intermediate code)
You can see the intermediate code with checking Trace in Settings.
When you check Trace, the private void trace(List<string> list)
method creates trace.txt
beside your FF bookmark file that includes intermediate code for generating an XML file.
After KingMark converts the List<string>
object to the XML file with the System.Xml.XmlWriter
class and the below method:
private void ListToXml(List<string> list)
{
string name = "";
string href = "";
string icon = "";
string iconUrl = "";
string desc = "";
string keyWords = "";
string addDate = "";
string lastModified = "";
try
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
//settings.NewLineOnAttributes = true;
settings.Encoding = Encoding.UTF8;
settings.ConformanceLevel = ConformanceLevel.Document;
System.Xml.XmlWriter Writer;
Writer = XmlWriter.Create(temporaryFileName, settings);
Writer.WriteStartDocument();
Writer.WriteComment(XmlDescription);
Writer.WriteStartElement(rootNodeName);
Writer.WriteAttributeString("ELEMENTS", list.Count.ToString());
for (int i = 1; i < list.Count; i++)
{
//Nodes separator
if (Regex.IsMatch(list[i], @"\<HR\>"))
{
//Writer.WriteStartElement("HR");
//Writer.WriteEndElement();
continue;
}
else if (Regex.IsMatch(list[i], @"\<NODE\>"))
{
//node's NAME
name = Regex.Match(list[i - 1].Trim(), "NAME=\"[^\"]*\"").ToString();
name = Regex.Replace(name, "NAME|\"|=", "");
//node's DESC
desc = Regex.Match(list[i - 1].Trim(),
"DESC=\"[^\"]*\"").ToString();
desc = Regex.Replace(desc, "DESC|\"|=", "");
//node's ADD_DATE
addDate = Regex.Match(list[i - 1].Trim(),
"ADD_DATE=\"[^\"]*\"").ToString();
addDate = Regex.Replace(addDate, "ADD_DATE|\"|=", "");
//node's LAST_MODIFIED
lastModified = Regex.Match(list[i - 1].Trim(),
"LAST_MODIFIED=\"[^\"]*\"").ToString();
lastModified = Regex.Replace(lastModified,
"LAST_MODIFIED|\"|=", "");
//\\
Writer.WriteStartElement("NODE" + i.ToString());
Writer.WriteAttributeString("NAME", name);
Writer.WriteAttributeString("ADD_DATE", addDate);
Writer.WriteAttributeString("LAST_MODIFIED", lastModified);
Writer.WriteAttributeString("DESC", desc);
}
else if (list[i].Trim() == "</NODE>")
{
if (i + 1 != list.Count)
Writer.WriteEndElement();
}
else if (!Regex.IsMatch(list[i + 1], @"\<NODE\>"))
{
//bookmark's name extracting
name = Regex.Match(list[i], "NAME=\"[^\"]*\"").ToString();
name = Regex.Replace(name, "NAME|\"|=", "");
//bookmark's address extracting
href = Regex.Match(list[i].Trim(),
"HREF=\"[^\"]*\"").ToString();
href = Regex.Replace(href, "HREF|\"|=", "");
//bookmark's icon's URL extracting
iconUrl = Regex.Match(list[i].Trim(),
"ICON_URI=\"[^\"]*\"").ToString();
iconUrl = Regex.Replace(iconUrl,
"ICON_URI|\"|=", "");
//bookmark's icon extracting
icon = Regex.Match(list[i].Trim(),
"ICON=\"[^\"]*\"").ToString();
icon = Regex.Replace(icon,
"\"|ICON|=", "");
//bookmark's description extracting
desc = Regex.Match(list[i].Trim(),
"DESC=\"[^\"]*\"").ToString();
desc = Regex.Replace(desc, "DESC|\"|=", "");
//bookmark's SHORTCUTURL extracting
keyWords = Regex.Match(list[i].Trim(),
"SHORTCUTURL=\"[^\"]*\"").ToString();
keyWords = Regex.Replace(keyWords,
"SHORTCUTURL|\"|=", "");
//ADD_DATE
addDate = Regex.Match(list[i].Trim(),
"ADD_DATE=\"[^\"]*\"").ToString();
addDate = Regex.Replace(addDate, "ADD_DATE|\"|=", "");
//LAST_MODIFIED
lastModified = Regex.Match(list[i].Trim(),
"LAST_MODIFIED=\"[^\"]*\"").ToString();
lastModified = Regex.Replace(lastModified,
"LAST_MODIFIED|\"|=", "");
//\\
/////////////////////////////////////////////////////////////
//write above data in XML file
Writer.WriteStartElement("BOOKMARK" + i.ToString());
Writer.WriteAttributeString("NAME", name.Trim());
Writer.WriteAttributeString("HREF", href.Trim());
Writer.WriteAttributeString("SHORTCUTURL", keyWords.Trim());
Writer.WriteAttributeString("DESC", desc.Trim());
Writer.WriteAttributeString("ADD_DATE", addDate.Trim());
Writer.WriteAttributeString("LAST_MODIFIED", lastModified.Trim());
Writer.WriteAttributeString("ICON_URI", iconUrl.Trim());
Writer.WriteAttributeString("ICON", icon.Trim());
Writer.WriteEndElement();
}
}
//Writing close tag for the root element.
Writer.WriteEndDocument();
Writer.Flush();
Writer.Close();
X_Element = XElement.Load(temporaryFileName);
}
catch (Exception ex)
{
StackFrame file_info = new StackFrame(true);
error(ref file_info, ex.Message);
}
}
XML File to TreeView
After creating the XML file, an XML file should be loaded in the TreeView control. (see below methods) If you check Load Icons in settings each icon of nodes will show.
///
/// Converts XML file to treeView
///
private void XmlToTree()
{
optimize_menuItem.Enabled = exportIE_favorites.Enabled =
exportXML_menuItem.Enabled =
exportHtml_menuItem.Enabled = true;
this.treeViewBookMark.Enabled = true;
this.XElementClopboard = null;
this.TreeNodeClipboard = null;
try
{
// SECTION 1. Create a DOM Document and load the XML data into it.
XmlDocument dom = new XmlDocument();
dom.Load(this.temporaryFileName);
// SECTION 2. Initialize the TreeView control.
treeViewBookMark.Nodes.Clear();
treeViewBookMark.Nodes.Add(new TreeNode(dom.DocumentElement.Name));
TreeNode tNode = new TreeNode(rootNodeName);
tNode = treeViewBookMark.Nodes[0];
tNode.Name = rootNodeName;
// SECTION 3. Populate the TreeView with the DOM nodes.
AddNode(dom.DocumentElement, tNode);
treeViewBookMark.SelectedNode = treeViewBookMark.Nodes[0];
selected_node = treeViewBookMark.Nodes[0];
treeViewBookMark.SelectedNode.Expand();
}
catch (Exception ex)
{
textBoxIconURL.Enabled = textBoxDesc.Enabled = textBoxName.Enabled
= buttonDelIcon.Enabled = textBoxKeyWords.Enabled
= textBoxHref.Enabled = false;
optimize_menuItem.Enabled = exportIE_favorites.Enabled
= exportXML_menuItem.Enabled = exportHtml_menuItem.Enabled
= false;
this.treeViewBookMark.Enabled = false;
StackFrame file_info = new StackFrame(true);
error(ref file_info, ex.Message);
return;
}
}
///
/// Creates treeView
/// References :
/// ms-help://MS.MSDNQTR.v90.en/enu_kbnetframeworkkb/netframeworkkb/317597.htm
/// http://support.microsoft.com/kb/317597
///
private void AddNode(XmlNode inXmlNode, TreeNode inTreeNode)
{
try
{
XmlNode xNode;
TreeNode tNode;
XmlNodeList nodeList;
int i;
int j = -1;
// Loop through the XML nodes until the leaf is reached.
// Add the nodes to the TreeView during the looping process.
if (inXmlNode.HasChildNodes)
{
nodeList = inXmlNode.ChildNodes;
for (i = 0; i <= nodeList.Count - 1; i++)
{
if (inXmlNode.ChildNodes[i].Name.Equals("HR"))
continue;
j++;
xNode = inXmlNode.ChildNodes[i];
TreeNode newTreeNode;
newTreeNode = new TreeNode(xNode.Attributes["NAME"].Value);
newTreeNode.Name = xNode.Name;
//تعیین عکس هر گره
//assigns icon of each node -> this code needs more process
if (loadIcons_menuItem.Checked)
{
Image icon = createIcon(xNode.Name);
if (Regex.IsMatch(inXmlNode.ChildNodes[i].Name, "NODE"))
{
newTreeNode.ImageIndex = 0;
newTreeNode.SelectedImageIndex = 0;
}
else if (icon != null && Regex.IsMatch(inXmlNode.ChildNodes[i].Name,
"BOOKMARK"))
{
imageList1.Images.Add(icon);
newTreeNode.ImageIndex = imageList1.Images.Count - 1;
newTreeNode.SelectedImageIndex = imageList1.Images.Count - 1;
}
else
{
newTreeNode.ImageIndex = 1;
newTreeNode.SelectedImageIndex = 1;
}
}
else
{
if (Regex.IsMatch(inXmlNode.ChildNodes[i].Name, "NODE"))
{
newTreeNode.ImageIndex = 0;
newTreeNode.SelectedImageIndex = 0;
}
else if (Regex.IsMatch(inXmlNode.ChildNodes[i].Name, "BOOKMARK"))
{
newTreeNode.ImageIndex = 1;
newTreeNode.SelectedImageIndex = 1;
}
}
//\\
inTreeNode.Nodes.Add(newTreeNode);
tNode = inTreeNode.Nodes[j];
AddNode(xNode, tNode);
}
}
else
{
// Here you need to pull the data from the XmlNode based on the
// type of node, whether attribute values are required, and so forth.
inTreeNode.Text = (inXmlNode.Attributes["NAME"].Value).Trim();
}
}
catch (Exception ex)
{
textBoxIconURL.Enabled = textBoxDesc.Enabled =
textBoxName.Enabled = buttonDelIcon.Enabled =
textBoxKeyWords.Enabled = textBoxHref.Enabled =
false;
optimize_menuItem.Enabled = exportIE_favorites.Enabled =
exportXML_menuItem.Enabled =
exportHtml_menuItem.Enabled = false;
treeViewBookMark.Nodes.Clear();
this.treeViewBookMark.Enabled = false;
StackFrame file_info = new StackFrame(true);
error(ref file_info, ex.Message);
return;
}
}
KingMark Features
TreeView Drag-n-Drop
You can export IE favorite files directly, using the Drag a TreeView folder or file out to the Window.
Unlike the above, you can import IE favorite files to KingMark with drag it into the TreeView.
Also, you can import IE6 (I had IE6, maybe on IE7 or IE8 doesn't work) website addresses and FF3 (I had FF3, maybe on FF2 or FF1 doesn't work) website tabs into KingMark with dragging it in its TreeView Control.
Exporting Bookmarks for Internet Explorer or Firefox Browser
With KingMark you can export all or part of bookmarks for FF(HTML file) or IE(*.url file)
For exporting all bookmarks use the Export Menu:
For exporting some bookmarks use TreeView's contextMenuStrip
:
Export for FF
Export for IE
Quick Search

I used LINQ to search the XML file (see below method)
private void textBoxSearchTxt_TextChanged(object sender, EventArgs e)
{
string searchTxt = Regex.Replace(textBoxSearchTxt.Text.Trim(),
@"[\$\^\{\[\(\|\)\*\+\?\\]", "");
if (searchTxt == "")
{
this.listView1.Items.Clear();
return;
}
try
{
var searchNodes = from nodes in X_Element.Descendants()
where
(nodes.Attribute("NAME") != null
Regex.IsMatch(nodes.Attribute("NAME").Value,
searchTxt, RegexOptions.IgnoreCase))
|| (nodes.Attribute("HREF") != null
Regex.IsMatch(nodes.Attribute("HREF").Value, searchTxt,
RegexOptions.IgnoreCase))
|| (nodes.Attribute("SHORTCUTURL") != null
Regex.IsMatch(nodes.Attribute("SHORTCUTURL").Value,
searchTxt,
RegexOptions.IgnoreCase))
select nodes;
listView1.Items.Clear();
foreach (var node in searchNodes)
{
try
{
ListViewItem item = new ListViewItem(new string[]
{ node.Attribute("NAME").Value, node.Attribute("HREF").Value });
item.Name = node.Name.ToString();
listView1.Items.Add(item);
}
catch
{
continue;
}
}
}
catch { }
}
Generating Website Preview Image
You can find WebsiteThumbnailImage.cs
in my project and figure out how I did it.
Notify Icon
When you minimize the KingMark window, KingMark creates a contextMenuStrip
with the TreeView nodes and show a notifyIcon
here:
And you can access to your bookmarks easily:
How can we convert TreeView to contextMenuStrip
:
I wrote these methods to do that, and these method did it well. But if you have a better way I thank you if you say it to me.
void createContextMenuStripNotifyIcon()
{
try
{
if (this.treeViewBookMark.Nodes.Count <= 0) return;
contextMenuStripNotifyIcon.Items.Clear();
foreach (TreeNode node in this.treeViewBookMark.Nodes[0].Nodes)
{
ToolStripMenuItem toolStripMenuItem = new ToolStripMenuItem();
if (node.GetNodeCount(true) > 0)
{
toolStripMenuItem.BackColor = contextMenuStripNotifyIcon.BackColor;
toolStripMenuItem.Image = imageList1.Images[node.ImageIndex];
toolStripMenuItem.Text = node.Text.Length > 30 ?
node.Text.Substring(0, 30) + " ..." : node.Text;
toolStripMenuItem.Name = node.Name;
createContextMenuStripNotifyIcon(node, ref toolStripMenuItem);
contextMenuStripNotifyIcon.Items.Add(toolStripMenuItem);
}
else
{
toolStripMenuItem.BackColor = contextMenuStripNotifyIcon.BackColor;
toolStripMenuItem.Image = imageList1.Images[node.ImageIndex];
toolStripMenuItem.Text = node.Text.Length > 30 ?
node.Text.Substring(0, 30) + " ..." : node.Text;
toolStripMenuItem.Name = node.Name;
toolStripMenuItem.MouseDown +=
new MouseEventHandler(contextMenuStripNotifyIconItems_MouseDown);
contextMenuStripNotifyIcon.Items.Add(toolStripMenuItem);
}
}
}
catch (Exception ex)
{
StackFrame file_info = new StackFrame(true);
error(ref file_info, ex.Message);
}
}
void createContextMenuStripNotifyIcon(TreeNode nodes,
ref ToolStripMenuItem toolStripMenuItem)
{
foreach (TreeNode node in nodes.Nodes)
{
if (node.GetNodeCount(true) > 0)
{
ToolStripMenuItem newToolStripMenuItem = new ToolStripMenuItem();
newToolStripMenuItem.BackgroundImage = imageList1.Images[node.ImageIndex];
newToolStripMenuItem.BackgroundImageLayout = ImageLayout.None;
newToolStripMenuItem.Text = node.Text.Length > 30 ?
node.Text.Substring(0, 30) + " ..." : node.Text;
newToolStripMenuItem.Name = node.Name;
createContextMenuStripNotifyIcon(node, ref newToolStripMenuItem);
toolStripMenuItem.DropDown.Items.Add(newToolStripMenuItem);
}
else
{
ToolStripMenuItem newToolStripMenuItem = new ToolStripMenuItem();
newToolStripMenuItem.BackgroundImage = imageList1.Images[node.ImageIndex];
newToolStripMenuItem.BackgroundImageLayout = ImageLayout.None;
newToolStripMenuItem.Text = node.Text.Length > 30 ?
node.Text.Substring(0, 30) + " ..." : node.Text;
newToolStripMenuItem.Name = node.Name;
newToolStripMenuItem.MouseDown +=
new MouseEventHandler(contextMenuStripNotifyIconItems_MouseDown);
toolStripMenuItem.DropDown.Items.Add(newToolStripMenuItem);
}
}
}
void contextMenuStripNotifyIconItems_MouseDown(object sender, MouseEventArgs e)
{
try
{
if (e.Button == MouseButtons.Left)
Process.Start(GetHref(((ToolStripMenuItem)sender).Name));
}
catch
{
StackFrame file_info = new StackFrame(true);
error(ref file_info, "Invalid URL");
}
}