General XMetaL Discussion

XMetaL Community Forum General XMetaL Discussion node list issues/questions

  • russurquhart1

    node list issues/questions

    Participants 8
    Replies 9
    Last Activity 13 years, 1 month ago

    Hi,

    As per my question the other day .re xpath, i wrote the following script to change all the filter attributes having the value 'filter5' to null:

        var nodelist = ActiveDocument.getNodesByXpath(“//*[@filter='filter5']”); 
                 
          Application.Alert(“Suspected elements to process: ” + nodelist.Length);
         
          var current = 0;
          var number_corrected = 0;
          while (current < nodelist.Length)
          {
            var current_node = nodelist.item(current);
                  current_node.setAttribute(“filter”, “”);
                  number_corrected = number_corrected + 1;
                  current = current + 1;
          }
          Application.Alert( (number_corrected  – 1) + ” filter attributes corrected”);

    My first alert, for example, says that there are a total of 26 suspected elements to process. The first pass through, only about 13 were processed.

    (I am assuming that, as i specified all elements, and that some of these elements may be contained in others, then only certain elements (siblings) are getting processed at a time. If this is the case, how can i change the loop to get them all in one swoop?

    Thanks!

    Russ

    Reply

    Derek Read

    Reply to: node list issues/questions

    One thing I don't think our docs state clearly (if at all) is that your “nodelist” variable is dynamic, meaning that changing the DOM node tree affects your variable (it might seem odd but that's the way it works).

    Here is a simplified example that does what your script is trying to do, which his to give all filter attributes that currently have a value of “filter5” a value of “” (empty string).

    [code]var nodelist = ActiveDocument.getNodesByXpath(“//*[@filter='filter5']”);
    var nodecount = nodelist.length;
    Application.Alert(“Fixing ” + nodecount + ” nodes…”);
    for (i=0; i nodelist.item(0).setAttribute(“filter”, “”);
    }[/code]

    Note: I assume you specifically wish to set the value to an empty string, rather than removing the attribute (which is technically different and will be treated differently by some XML processors). If you want to remove the attribute instead you can use this: nodelist.item(0).removeAttribute("filter")

    Reply

    russurquhart1

    Reply to: node list issues/questions

    That did the trick!

    As i was experimenting, i was looking at the length noticing that each time through the loop, that number was decreasing, and i couldn't figure out why.

    So is the dynamic nature of the node list tied to the initial Xpath declaration, i.e. as i changed the attribute to “” the number of nodes in the node list decreased? Is that where the dynamic nature comes in?

    Thanks,

    Russ

    Reply

    Derek Read

    Reply to: node list issues/questions

    It is tied more directly to your nodelist object (variable) and the values it contains, so that (in theory) if you were to iterate through the list of nodes once and set the attribute values, then iterate through a second time and read the attribute values the read operation would reflect the current state after the first iteration (not the original state) of the document's nodes. The confusion that most people might have with this is that you are not dealing with things purely in script here, you are actually making real modifications to the document.

    Reply

    russurquhart1

    Reply to: node list issues/questions

    Not to beat a dead horse, but trying to get my mind around this. In a previous script i wrote something like:

    var nodelist = ActiveDocument.getNodesByXPath(“//entry[@role='hdr']/ancestor::GenTable[1]”);

          var current = 0;
          var number_corrected = 0;
          while (current < nodelist.length)
          {
            var current_node = nodelist.item(current);
              current_node.setAttribute(“role”, “Register”);
              current_node.setAttribute(“columns”, “1”);
              number_corrected = number_corrected + 1;
              current = current + 1;
          }

    I iterate through the nodelist, and this works. (From what you said previously, i would think it wouldn't.) Is this list not affected because the nodes that were the basis for the selection, their attribute values, remain unchanged and only attribute values for their ancestors are changed?

    Sorry still a little confused.

    Thanks,

    Russ

    Reply

    Derek Read

    Reply to: node list issues/questions

    Our DOMNodeList object implements a “live” list. The W3C XPath specification recommends not to do this but doesn’t preclude us from doing it. For XMetaL it was the best solution (there are other features we support involved here that are affected as well).

    The property DOMNodeList.length is also “live” and re-evaluates every time the property is accessed (as you have seen).

    Reply

    frances

    Reply to: node list issues/questions

    I'm also pretty confused about DomNodeList.
    I'm trying to iterate through a node list and change the type of each element found. With my current approach, the script misses every other element, so only half of the elements in a doc get changed.

    My current approach was to get inside the element's contents, then change its container name. (sorry for the horrible following formatting:)

    [code]//create a Range object to manipulate
        rngText = ActiveDocument.Range;

    foundTagsList = ActiveDocument.getElementsByTagName(“draft-comment”);
        for (var j=0; j < foundTagsList.length; j++){
            element = foundTagsList.item(j);
            //convert the node into a selection (using Range)
            rngText.SelectNodeContents(element);
            //get the node's contents w/o containing tags
            rngText.SelectContainerContents();
            if (rngText.CanChange(“note”)) {
              rngText.ContainerName = “note”;
                }
          }[/code]

       

    background: my goal is to turn each into a certain type of so that in my PDF output, reviewers can see my questions. (I'll also later turn all those types of notes back into draft-comments)

    Reply

    Derek Read

    Reply to: node list issues/questions

    @frances

    I think to do what you want to do you would have to change the nodes in reverse order (reverse the loop).

    However, I think in this particular case the following script will run quite a bit faster:

    [code]//XMetaL Script Language JScript:
    rng = ActiveDocument.Range;
    rng.MoveToDocumentStart();
    while(rng.MoveToElement(“draft-comment”)) {
    if(rng.CanChange(“note”)) {
    rng.ContainerName = “note”;
    }
    }[/code]

    Reply

    Derek Read

    Reply to: node list issues/questions

    Since each change is causing the document to update it would make it even faster (and stop flickering) to turn off document updating at the start and end. This issue will be more noticeable when there are many draft-comment elements in a larger document.

    [code]//XMetaL Script Language JScript:
    ActiveDocument.FormattingUpdating = false;
    rng = ActiveDocument.Range;
    rng.MoveToDocumentStart();
    while(rng.MoveToElement(“draft-comment”)) {
    if(rng.CanChange(“note”)) {
    rng.ContainerName = “note”;
    }
    }
    ActiveDocument.FormattingUpdating = true;[/code]

    Reply

    Derek Read

    Reply to: node list issues/questions

    @frances

    Here's your original, rewritten:

    [code]ActiveDocument.FormattingUpdating = false;
    var rngText = ActiveDocument.Range;
    foundTagsList = ActiveDocument.getElementsByTagName(“draft-comment”);
    while (foundTagsList.length > 0){
    element = foundTagsList.item(0);
    //convert the node into a selection (using Range)
    rngText.SelectNodeContents(element);
    //get the node's contents w/o containing tags
    rngText.SelectContainerContents();
    if (rngText.CanChange(“note”)) {
    rngText.ContainerName = “note”;
    }
    }
    ActiveDocument.FormattingUpdating = true;[/code]

    I've compared the length of time it takes to run both on the same document (an extreme case containing 1,000 draft-comment elements). The simplified version that does not use getElementsByTagName runs about 18% faster (13.6 seconds vs 11.1 seconds) and so not a big difference. For a much shorter and smaller document (which if this is DITA is almost certain to be the case) it would probably not be noticeable.

    Looking at it again though, I don't think there's much point in doing the CanChange check. If the call to setting the ContainerName (used to change the element) was to fail then the nodelist would not get any smaller and so the loop would never finish (either as a while or a for loop). I think using this logic you'd probably want to bail out of the loop instead (if there is a possibility of failure) or it would need to be rewritten.

    Reply

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

Lost Your Password?

Products
Downloads
Support