Firefox 书签管理器(使用 C# 和 XML)






4.47/5 (27投票s)
使用 KingMark,


引言
这是一个简单的 Firefox 书签管理器。使用 KingMark,您可以将 Firefox 书签导入、管理并导出为 HTML 或 *.url 或 XML 文件。KingMark 使用 XML,首先将 Firefox 书签文件转换为 XML 文件,然后将其转换为 HTML 文件。
Using the Code
创建 XML 文件
KingMark 为每个节点创建具有唯一名称的 XML 文件。例如,这是 XML 文件中的一个节点
<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>
正如您所看到的,每个节点都有一个唯一的名称,所以我使用这些名称来命名 TreeView 节点名称。通过这种命名方式,我们可以轻松地在 XML 文件和 TreeView 控件中找到每个节点。
我将最大的节点号(例如:<BOOKMARK13 ... />)保存在根节点的属性 (ELEMENTS
) 中。通过此属性,我们可以找到命名中使用的最新数字,并在此之后开始命名。通过 OPTIMIZE XML FILE,KingMark 会排列 XML 元素。
首先:KingMark 将 FF BookMark 文件(HTML 文件)转换为 List<string>
对象(中间代码)
您可以通过在“设置”中检查跟踪来查看中间代码。
当您选中“跟踪”时,private void trace(List<string> list)
方法会在您的 FF 书签文件旁边创建一个 trace.txt
文件,其中包含用于生成 XML 文件的中间代码。
在 KingMark 将 List<string>
对象转换为 XML 文件后,使用 System.Xml.XmlWriter
类和以下方法
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 文件到 TreeView
创建 XML 文件后,应将 XML 文件加载到 TreeView 控件中。(见下述方法) 如果您在设置中选中“加载图标”,则将显示每个节点的图标。
///
/// 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 功能
TreeView 拖放
您可以直接导出 IE 收藏夹文件,使用拖动 TreeView 文件夹或文件到窗口。
与上述不同的是,您可以将 IE 收藏夹文件拖到 KingMark 的 TreeView 中来导入它们。
此外,您还可以将 IE6(我有 IE6,可能在 IE7 或 IE8 上不起作用)网站地址和 FF3(我有 FF3,可能在 FF2 或 FF1 上不起作用)网站标签拖入 KingMark 的 TreeView 控件中。
为 Internet Explorer 或 Firefox 浏览器导出书签
使用 KingMark,您可以为 FF (HTML 文件) 或 IE (*.url 文件) 导出所有或部分书签
要导出所有书签,请使用“导出”菜单
要导出部分书签,请使用 TreeView 的 contextMenuStrip
导出到 FF
导出到 IE
快速搜索

我使用 LINQ 来搜索 XML 文件(见下述方法)
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 { }
}
生成网站预览图像
您可以在我的项目中找到 WebsiteThumbnailImage.cs
,并了解我是如何做到的。
通知图标
当您最小化 KingMark 窗口时,KingMark 会创建一个带有 TreeView 节点的 contextMenuStrip
并在其中显示一个 notifyIcon
并且您可以轻松访问您的书签
我们如何将 TreeView 转换为 contextMenuStrip
我编写了这些方法来执行此操作,并且这些方法运行良好。但是,如果您有更好的方法,如果您告诉我,我将感谢您。
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");
}
}