General XMetaL Discussion

XMetaL Community Forum General XMetaL Discussion Finding and returning exact insert location

  • pooh2583

    Finding and returning exact insert location

    Participants 3
    Replies 4
    Last Activity 9 years, 9 months ago


    I wnt to insert a node  at a valid location

    I have used Selection.FindInsertLocation(“para”); to find a valid location for para

    like if my element structure is like this

    (this is my valid location for para)

    Now I have a node which is copied from the same document using cloneNode(true)
    var elempara = paraelem.cloneNode(true);

    and I want to insert this elempara node at the specified valid location as shown above

    using insert or append

    How do I get the exact Selection location where I can insert this node and how can I insert it over there?

    is there any way to get the exact location location found from Selection.FindInsertLocation();

    please reply



    Derek Read

    Reply to: Finding and returning exact insert location

    When you call FindInsertLocation() it actually moves the Selection (or Range if you are using Range) to the next valid position where the specified element is allowed to be inserted, so there is nothing more to find or move. The selection is already there.

    However, it sounds like you are mixing the use of DOM and Selection/Range? That complicates things a bit as these are different concepts (and modelled differently inside XMetaL and require the use of APIs on different objects). There are APIs to “convert” from one to the other but how you mix the two (and even if you can do it) depends on what you are doing.

    After calling FindInsertLocation() your Selection is exactly where you indicate in your example. So, if you wish to use that as the insertion point but then use a DOM call to do the insertion you will need to convert the Selection into a DOM node using Selection.ContainerNode. Once you have that node you can call insertBefore() or appendChild().

    Unfortunately the node your selection is inside of is . So, calling insertBefore() will end up trying to put your copied node before . That is not what you want. Calling appendChild() will try to add your copied node to the end of and that is not what you want either.

    To use these DOM calls for insertion I think you would need to somehow find and then call insertBefore(), or move the selection using Selection.MoveRight(), Selection.GotoNext(), or maybe even Selection.MoveToElement(“node3”), after your call to FindInsertLocation(). However, that doesn't seem very robust to me.

    Have a look at the code example in the Programmers Guide for “createDocumentFragment”. I think it is a good example for mixing DOM and the Selection / Range objects.

    It might be far simpler to not use DOM at all. Instead of using clodeNode() earlier on in your script to copy the element you would start right from the beginning by moving the Selection around (better to use Range in most cases actually as it can get to more places than a regular user can, and it is generally invisible to the user) then copy whatever Selection you end up building using Selection/Range.Text (or Selection/Range.TextWithRM if you need to copy change tracking as well). Then after you move the Selection to the insertion position (where you want to move/copy the element to) you would just call Selection.PasteString().

    Most people find scripting with the Selection/Range objects to be easier than DOM. However, there are probably only rare cases where you might want to mix their use, so if you start with DOM then it can be easiest to use it all the way through your script as well.

    What does your exact XML look like before and afterwards? You will need to include all attrs and children so I have a really good idea of what you are doing.

    Can we use the user's current selection as the starting point for finding the element to copy? If not, what criteria are you using to locate that element (element name, parent, children, PCDATA, PI, attribute values, etc.)?



    Reply to: Finding and returning exact insert location


    I use “XMetal Author Entreprise 9.0” and I have a problem with inserting at correct location.

    My XML file has a number of “” elements which contain each a “” element.</p> <p><documentinfo><br />  <title>…

    My XML shema specify that “” tag must be inserted after “” element.</p> <p>When using my macro, the “<language>” element is always inserted before the “<title>” and not after.</p> <p>“…<br />AddElement(“//documentInfo”, “language”, elementValue);<br />…”</p> <p>function AddElement(elementsName, elementName, elementValue)<br />{    <br />    var objNode = ActiveDocument.documentElement;<br />    var objNodesList = objNode.getNodesByXPath(elementsName);</p> <p>    for (var index = 0; index < objNodesList.length; index++)<br />    {<br />        objRange = ActiveDocument.Range;<br />        objRange.SelectNodeContents(objNodesList.item(index));<br />        objRange.SelectElement();<br />        objRange.Collapse(1);<br />        if (objRange.FindInsertLocation(elementName, true))<br />        {<br />            objRange.InsertWithTemplate(elementName);<br />            objRange.TypeText (elementValue);<br />        }<br />        else<br />        {<br />            ActiveDocument.Host.Alert(“Insert location not found.”);<br />        }        <br />    }            <br />}</p> <p>***</p> <p>Other problem :</p> <p>When “objRange” is “<practiceareas>” which is an element which contain “<practicearea>“, the instruction “objRange.FindInsertLocation(“practiceArea”, true)” won't find any valid insert location.</p> <p>Final ouput should be</p> <p><documentinfo><br />  <title>…


    Derek Read

    Reply to: Finding and returning exact insert location

    I'm not sure about your first issue, but I'm going to guess 2 things:

    1. Your schema does actually allow to appear before . If it did not then I would not expect FindInsertLocation() to move the range there.
    2. Part of your issue might be with your call to Collapse(1). If I understand what your code is doing it is selecting all of then collapsing to the start, which is before the . I guess you should actually be collapsing to the end, or you should be finding the and then moving the Range after it. Depending on what your document content looks like in real world use you might actually want to do the latter.</p> <p>Regarding your “other” issue:<br />I think I'd need to see a working example. If you want to submit one to XMetaL Support that would be best, unless you don't mind sharing it on the forum. However, I would recommend that you check to see that your starting range is before the valid insert location. If it isn't then that's your issue, or you need to call it with the <tt>boolSearchForward</tt> parameter set to false.



    Reply to: Finding and returning exact insert location

    Hello and thanks for your reply.

    Found something related to first problem :

    “language” element is required by shema and before inserting this element, the document is not valid related to this shema as “language” element is missing.
    Any attempt to use “FindInsertLocation” to insert element at correct location won't function as long as the document is not valid at the moment you use the function, even if this function give a “true” statement back.

    When I modify my schema to make “language” an optionnal element, the problem is resolved.


  • You must be logged in to reply to this topic.

Lost Your Password?