none
Sorting Word Bookmarks as per w:id's. RRS feed

  • Question

  • Hello Everyone,

    I am creating one application, where I am reading the document.xml and then accessing the w:bookmarkStart and w:bookmarkEnd for getting some information. While traversing, I found that sometimes, the w:bookmarkStart and w:bookmarkEnd are not arranged as per w:id values. Lets say an example:

    <w:p>
     <w:bookmarkStart w:id="1" />
     <w:bookmarkStart w:id="3" />
     <w:bookmarkStart w:id="2" />
     <w:r><w:t>First Name</w:t></w:r>
     <w:bookmarkEnd w:id="3"/>
     <w:bookmarkEnd w:id="1"/>
     <w:bookmarkEnd w:id="2"/>
    </w:p> 

    Here you can see that the bookmarks are not arranged as per w:id sequences. Now, I want to convert the sequence in the same XML as follows:

    <w:p>
     <w:bookmarkStart w:id="1" />
     <w:bookmarkStart w:id="2" />
     <w:bookmarkStart w:id="3" />
     <w:r><w:t>First Name</w:t></w:r>
     <w:bookmarkEnd w:id="3"/>
     <w:bookmarkEnd w:id="2"/>
     <w:bookmarkEnd w:id="1"/>
    </w:p> 

    Let me know, how to arrange it programmatically in C#. Also, I need to keep the performance part as well, as I will be using large size Word documents.

    Thanks,


    Shahab Abbasi

    Thursday, June 8, 2017 6:16 AM

Answers

  • Hello,

    If that is your want, we could use Dictionary<TKey, TValue> Class to store and retrieve the name based on its id and then assign to bookmarks.

    E.g.

                 int id;
                    string bmName;
                    Dictionary<int, string> dict = new Dictionary<int, string>();
                    foreach (BookmarkStart bmStart in body.Descendants<BookmarkStart>())
                    {
                        id = Int32.Parse(bmStart.Id.InnerText);
                        bmName = bmStart.Name;
                        dict.Add(id, bmName);
                    }
                    foreach (KeyValuePair<int, string> pair in dict)
                    {
                        Console.WriteLine("Key: {0}, Value: {1}", pair.Key, pair.Value);
                    }
                  
                    int i = 0;
                    foreach (BookmarkStart bmStart in body.Descendants<BookmarkStart>())
                    {
                        bmStart.Id = i.ToString();
                        bmStart.Name = dict[i];
                        Console.WriteLine(dict[i]);
                        i++;
                        Console.WriteLine(bmStart.OuterXml);
                        Console.WriteLine(bmStart.Id);
                        Console.WriteLine(bmStart.Name);
                    }
                    i = i - 1;
                    foreach (BookmarkEnd bmEnd in body.Descendants<BookmarkEnd>())
                    {
                        bmEnd.Id = i.ToString();
                        i--;
                        Console.WriteLine(bmEnd.OuterXml);
                        Console.WriteLine(bmEnd.Id);
                    }

    Regards,

    Celeste


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, June 13, 2017 3:26 AM
    Moderator

All replies

  • Hello,

    You could use the following code to arrange these bookmarks. However, I don't suggest re-assign the id because it would mess up all the bookmarks. According to the XML, it seems there are three bookmarks for one string, I think you need to check that. And If there are several <w:r><w:t> between these bookmark tags, the two samples identify totally different bookmarks.

                    int i = 1;
                    foreach (BookmarkStart bmStart in para.Descendants<BookmarkStart>())
                    {
                        bmStart.Id = i.ToString();
                        i++;
                        Console.WriteLine(bmStart.OuterXml);
                        Console.WriteLine(bmStart.Id);
                    }
                    i = i - 1;
                    foreach (BookmarkEnd bmEnd in para.Descendants<BookmarkEnd>())
                    {
                        bmEnd.Id = i.ToString();
                        i--;
                        Console.WriteLine(bmEnd.OuterXml);
                        Console.WriteLine(bmEnd.Id);
                    }

    Regards,

    Celeste


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, June 9, 2017 7:05 AM
    Moderator
  • Hello Caleste,

    Your solution will only re-assign the ids. You know that with every bookmarksStart, there is a w:name, if we replace the id's, bookmark will loose the exact information. Let me make it more clear: Here is the input paragraph, it may have several <w:r> surrounded with bookmarks.

    <w:p>
     <w:bookmarkStart w:name="A" w:id="1" />
     <w:bookmarkStart w:name="c" w:id="3" />
     <w:bookmarkStart w:name="B" w:id="2" />
     <w:r><w:t>First Name</w:t></w:r>
     <w:bookmarkEnd w:id="3"/>
     <w:bookmarkEnd w:id="1"/>
     <w:bookmarkEnd w:id="2"/>
    </w:p>

    Now, my final converted XML should look like this:

    <w:p>
     <w:bookmarkStart w:name="A" w:id="1" />
     <w:bookmarkStart w:name="B" w:id="2" />
     <w:bookmarkStart w:name="C" w:id="3" />
     <w:r><w:t>First Name</w:t></w:r>
     <w:bookmarkEnd w:id="3"/>
     <w:bookmarkEnd w:id="2"/>
     <w:bookmarkEnd w:id="1"/>
    </w:p> 

    Bookmark w:id should shift along with w:name as well.

    Let me know, if you have any questions.

    Thanks,


    Shahab Abbasi


    Friday, June 9, 2017 1:19 PM
  • Hello,

    Re-assign with the name would not be difficult, we could store the name and id it in a two-dimensional array. The issue is that bookmark use id to recognize its bookmark range. Reassigning the ids would edit the bookmark range.

    For example, we have the XML as

    <w:p>
     <w:bookmarkStart w:name="A" w:id="1" />、
     <w:r><w:t>Test1</w:t></w:r>
     <w:bookmarkStart w:name="c" w:id="3" />
     <w:r><w:t>Test2</w:t></w:r>
     <w:bookmarkStart w:name="B" w:id="2" />
     <w:r><w:t>Test3</w:t></w:r>
     <w:bookmarkEnd w:id="3"/>
     <w:bookmarkEnd w:id="1"/>
     <w:bookmarkEnd w:id="2"/>
    </w:p>

    It indicates there are three bookmarks

    A: Test1Test2Test3

    B: Test3

    C: Test2Test3

    If you change the xml into

    <w:p>
     <w:bookmarkStart w:name="A" w:id="1" />
     <w:r><w:t>Test1</w:t></w:r>
     <w:bookmarkStart w:name="B" w:id="2" />
     <w:r><w:t>Test2</w:t></w:r>
     <w:bookmarkStart w:name="C" w:id="3" />
     <w:r><w:t>Test3</w:t></w:r>
     <w:bookmarkEnd w:id="3"/>
     <w:bookmarkEnd w:id="2"/>
     <w:bookmarkEnd w:id="1"/>
    </w:p> 

    The three bookmarks would be changed into

    A: Test1Test2Test3

    B: Test2Test3

    C: Test3

    Is that what you want?


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, June 12, 2017 6:59 AM
    Moderator
  • Yes Celeste,

    You reached exactly which I am looking for.

    Thanks,


    Shahab Abbasi

    Monday, June 12, 2017 10:33 AM
  • Hello,

    If that is your want, we could use Dictionary<TKey, TValue> Class to store and retrieve the name based on its id and then assign to bookmarks.

    E.g.

                 int id;
                    string bmName;
                    Dictionary<int, string> dict = new Dictionary<int, string>();
                    foreach (BookmarkStart bmStart in body.Descendants<BookmarkStart>())
                    {
                        id = Int32.Parse(bmStart.Id.InnerText);
                        bmName = bmStart.Name;
                        dict.Add(id, bmName);
                    }
                    foreach (KeyValuePair<int, string> pair in dict)
                    {
                        Console.WriteLine("Key: {0}, Value: {1}", pair.Key, pair.Value);
                    }
                  
                    int i = 0;
                    foreach (BookmarkStart bmStart in body.Descendants<BookmarkStart>())
                    {
                        bmStart.Id = i.ToString();
                        bmStart.Name = dict[i];
                        Console.WriteLine(dict[i]);
                        i++;
                        Console.WriteLine(bmStart.OuterXml);
                        Console.WriteLine(bmStart.Id);
                        Console.WriteLine(bmStart.Name);
                    }
                    i = i - 1;
                    foreach (BookmarkEnd bmEnd in body.Descendants<BookmarkEnd>())
                    {
                        bmEnd.Id = i.ToString();
                        i--;
                        Console.WriteLine(bmEnd.OuterXml);
                        Console.WriteLine(bmEnd.Id);
                    }

    Regards,

    Celeste


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, June 13, 2017 3:26 AM
    Moderator