Click here to Skip to main content
Click here to Skip to main content

Merge Firefox json bookmarks

, 5 Nov 2012
Rate this:
Please Sign up or sign in to vote.
A utility to merge 2 firefox json bookmark files while preserving tags, and directory struction

Introduction 

If you want to merge bookmarks from 2 machines (ex, work and home) firefox doesn't allow you to merge the bookmarks, it only allow you to replace the current bookmarks.

Background  

this code use jayrock json library to manipulate json text 

http://jayrock.berlios.de

Using the code

firefox bookmark file, are composed mainly of 4 arrays, Tags, Bookmark Menu, Bookmark Toolbar and unsorted bookmark.
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());
        }
    }
}



Points of Interest

jayrock json library is very nice and easy to use tool

History

 first release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

AmrEmam

Canada Canada
No Biography provided

Comments and Discussions

 
QuestionHow to use thia code? PinmemberSimon K B12-Feb-13 4:28 
QuestionHow do I use this exactly? Pinmember5moufl28-Aug-12 23:08 
GeneralMy vote of 4 PinmemberKlaus Luedenscheidt17-Jun-12 17:18 
GeneralRe: My vote of 4 PinmemberAmrEmam20-Jun-12 13:08 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140721.1 | Last Updated 5 Nov 2012
Article Copyright 2012 by AmrEmam
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid