合并 Firefox json 书签
一个实用工具,用于合并两个 Firefox JSON 书签文件,同时保留标签和目录结构。
介绍
如果你想合并两台机器(例如,工作和家庭)的书签,Firefox 不允许你合并书签,它只允许你替换当前的书签。
背景
这段代码使用 Jayrock JSON 库来操作 JSON 文本。
使用代码
Firefox 书签文件主要由 4 个数组组成:标签、书签菜单、书签工具栏和未排序的书签。using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Jayrock.Json.Conversion;
using System.Collections;
using System.Windows.Forms;
namespace mergeBookmarks
{
static class Merge
{
static int maxId = 0;
static IDictionary findItem(string menu, string sUri, Jayrock.Json.JsonArray jArray)
{
IDictionary foundNode = null;
int i;
for (i = 0; i < jArray.Count(); i++)
{
if (jArray[i].GetType() == typeof(Jayrock.Json.JsonObject))
{
IDictionary node =(IDictionary) jArray[i];
if (node.Contains("title"))
{
if ((node["title"] == null && menu == null) || Convert.ToString(node["title"]).Equals(menu))
{
foundNode = (IDictionary)jArray[i];
if (node.Contains("uri"))
{
if (Convert.ToString(node["uri"]).Equals(sUri))
{
return foundNode;
}
}
else
{
return foundNode;
}
}
}
}
else if (jArray[i].GetType() == typeof(Jayrock.Json.JsonArray))
{
}
else
{
}
}
return foundNode;
}
static int findMaxIndex(Jayrock.Json.JsonArray jArray)
{
int index = 0;
int i;
for (i = 0; i < jArray.Count(); i++)
{
if (jArray[i].GetType() == typeof(Jayrock.Json.JsonObject))
{
IDictionary node =(IDictionary)jArray[i];
if (node.Contains("index"))
{
if (Convert.ToInt32(node["index"])>index)
index = Convert.ToInt32(node["index"]);
}
}
else
{
}
}
return index;
}
static void adjustIds( int parent, Jayrock.Json.JsonArray jArray)
{
IEnumerator<object> jTagEnum = jArray.GetEnumerator();
int index = 0;
while (jTagEnum.MoveNext())
{
IDictionary obj= (IDictionary)jTagEnum.Current;
obj["id"] = maxId++;
obj["parent"] = parent;
if (!obj.Contains("index"))
{
if (index > 0)
obj.Add("index", index);
}
else
{
obj["index"] = index;
}
index++;
if (obj["type"].ToString().Equals("text/x-moz-place-container"))
{
adjustIds(Convert.ToInt32(obj["id"]), (Jayrock.Json.JsonArray)obj["children"]);
}
}
}
static void doMergeLists(IDictionary node1, IDictionary node2)
{
string sType1, sType2;
sType1 = node1["type"].ToString();
sType2 = node2["type"].ToString();
if (!sType1.Equals("text/x-moz-place-container") || !sType2.Equals("text/x-moz-place-container"))
{
throw new Exception("not container");
}
Jayrock.Json.JsonArray jArray1 = (Jayrock.Json.JsonArray)node1["children"];
int TagsId = Convert.ToInt32(node1["id"]);
Jayrock.Json.JsonArray jArray2 = (Jayrock.Json.JsonArray)node2["children"];
int maxTagsIndex = findMaxIndex(jArray1) + 1;
IEnumerator<object> jArray2Enum = jArray2.GetEnumerator();
while (jArray2Enum.MoveNext())
{
IDictionary node = (IDictionary)jArray2Enum.Current;
if (node.Contains("title"))
{
string title=null;
if (node["title"] != null)
title = node["title"].ToString();
else
title = null;
string sItemType2 = node["type"].ToString();
if ((title != null && (title.Equals("Recently Bookmarked") || title.Equals("Recent Tags"))) || sItemType2 == "text/x-moz-place-separator")
{
continue;
}
IDictionary obj = null;
if (node.Contains("uri"))
{
string sUri = node["uri"].ToString();
obj = findItem(title, sUri, jArray1);
}
else
{
obj = findItem(title, "", jArray1);
}
if (obj != null)
{
string sItemType1 = obj["type"].ToString();
if (sItemType1.Equals(sItemType2))
{
// equal Types, then will do merge
if(sItemType1.Equals("text/x-moz-place"))
{
string sUri = node["uri"].ToString();
if (node["uri"].ToString().Equals(obj["uri"].ToString()))
{
// equal title and uri, do nothing
}
else
{
// equal title, but different uri, rename node
int i = 1;
IDictionary tObj;
if (title != null)
{
while ((tObj = findItem(title + "(" + i + ")", sUri, jArray1)) != null)
{
i++;
}
}
string obj1Text = node.ToString();
if (!node.Contains("index"))
{
obj1Text = obj1Text.Insert(1, "\"index\":" + maxTagsIndex.ToString() + ",");
}
IDictionary obj1 = (IDictionary)JsonConvert.Import(obj1Text);
int objId = maxId++;
if(title != null)
obj1["title"] = obj1["title"].ToString() + "(" + i + ")";
obj1["id"] = objId;
obj1["parent"] = TagsId;
obj1["index"] = maxTagsIndex++;
if (obj1["type"].ToString().Equals("text/x-moz-place-container"))
adjustIds(objId, (Jayrock.Json.JsonArray)obj1["children"]);
jArray1.Add(obj1);
}
}
else
{
// merge lists
doMergeLists(obj, node);
}
}
else
{
// types not equal, rename node
int i = 1;
IDictionary tObj;
string sUri1 = null;
if(node.Contains("uri"))
sUri1 = node["uri"].ToString();
while ((tObj = findItem(title + "(" + i + ")",sUri1, jArray1)) != null)
{
i++;
}
string obj1Text = node.ToString();
if (!node.Contains("index"))
{
obj1Text = obj1Text.Insert(1, "\"index\":" + maxTagsIndex.ToString() + ",");
}
IDictionary obj1 = (IDictionary)JsonConvert.Import(obj1Text);
int objId = maxId++;
obj1["title"] = obj1["title"].ToString() + "(" + i + ")";
obj1["id"] = objId;
obj1["parent"] = TagsId;
obj1["index"] = maxTagsIndex++;
adjustIds(Convert.ToInt32(obj1["id"]), (Jayrock.Json.JsonArray)obj1["children"]);
jArray1.Add(obj1);
}
}
else
{
// not duplicate node
string obj1Text = node.ToString();
if (!node.Contains("index"))
{
obj1Text = obj1Text.Insert(1, "\"index\":" + maxTagsIndex.ToString() + ",");
}
IDictionary obj1 = (IDictionary)JsonConvert.Import(obj1Text);
int objId = maxId++;
obj1["id"] = objId;
obj1["parent"] = TagsId;
obj1["index"] = maxTagsIndex++;
if(sItemType2.Equals("text/x-moz-place-container"))
adjustIds(Convert.ToInt32(obj1["id"]), (Jayrock.Json.JsonArray)obj1["children"]);
jArray1.Add(obj1);
}
}
}
}
static int findMaxId( ref int id,Jayrock.Json.JsonArray jArray )
{
int i;
for (i = 0; i < jArray.Count(); i++)
{
if (jArray[i].GetType() == typeof(Jayrock.Json.JsonObject))
{
findMaxId(ref id, (IDictionary)jArray[i]);
}
else if (jArray[i].GetType() == typeof(Jayrock.Json.JsonArray))
{
findMaxId(ref id, (Jayrock.Json.JsonArray)jArray[i]);
}
else
{
// parseItem(jArray[i]);
Console.WriteLine(" {0,-25} {1}", ((DictionaryEntry)jArray[i]).Key, ((DictionaryEntry)jArray[i]).Value.GetType().ToString(), ((DictionaryEntry)jArray[i]).Value.ToString());
}
}
return id;
}
static int findMaxId(ref int id, IDictionary node)
{
if(node.Contains("id")){
if(Convert.ToInt32( node["id"]) > id)
id=Convert.ToInt32(node["id"]);
}
IDictionaryEnumerator dict = node.GetEnumerator();
while (dict.MoveNext())
{
if (dict.Value == null)
{
}
else if (dict.Value.GetType() == typeof(Jayrock.Json.JsonArray))
{
findMaxId(ref id, (Jayrock.Json.JsonArray)dict.Value);
}
else if (dict.Value.GetType() == typeof(Jayrock.Json.JsonObject))
{
findMaxId(ref id, (IDictionary)dict.Value);
}
}
return id;
}
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmMerge());
}
public static void MergeBookmarks(string srcFile1, string srcFile2, string DstFile)
{
string jsontext = System.IO.File.ReadAllText(srcFile1);
IDictionary root1 = (IDictionary)JsonConvert.Import(jsontext);
jsontext = System.IO.File.ReadAllText(srcFile2);
IDictionary root2 = (IDictionary)JsonConvert.Import(jsontext);
int id = 0;
findMaxId(ref id, root1);
maxId = id+1;
doMergeLists(root1, root2);
System.IO.File.WriteAllText(DstFile, root1.ToString());
}
}
}
关注点
Jayrock JSON 库是一个非常优秀且易于使用的工具。
历史
首次发布