javascriptadobe-indesignextendscript

Find in InDesign frame symbols not marked with a certain tag, and mark them with another tag


I have a structured Indesign document. I select a text frame with text, in which some symbols are marked by an XML tag 'XXX'. I want to mark all the rest text in this story with a tag 'YYY'.

I've tried this code:

var mySelection = app.selection[0]; // Get the selected frame
var tagToApply = "YYY"; // Tag to apply 
var tagToSkip = "XXX"; // Tag to skip
var myTextFrame = mySelection;
var myTexts = myTextFrame.texts;
var myStory = myTextFrame.parentStory;

// Function to check if the text is not marked with tag to skip
function isUntagged(text) {
    return text.associatedXMLElements.name !== tagToSkip;
}

// Check all the text in the selected frame
for (var i = 0; i < myTexts.length; i++) {
    var thisText = myTexts[i];
    if (isUntagged(thisText)) {
        // Mark the found untagged text with the tag to apply
        var myXMLElement = app.activeDocument.xmlElements.item(0).xmlElements.add(tagToApply, thisText);
    }
}

The problem is that all the story text is marked with 'YYY' tag, including the fragments tagged as 'XXX'.


Solution

  • Probably you want something like this:

    var frame = app.selection[0];
    if (!(frame instanceof TextFrame)) exit();
    
    var tag_to_apply = 'YYY';
    var tag_to_skip = 'XXX';
    
    var characters = frame.parentStory.characters;
    // var characters = frame.parentStory.words; // <-- if you don't need to include the spaces
    
    var start = 0, end = 0;
    while (end < characters.length) {
    
        // get the end of unttaged text
        while (characters[end].associatedXMLElements[0].markupTag.name != tag_to_skip) {
            end++;
            if (end >= characters.length) break;
        }
    
        // apply the tag from the start to the end
        app.activeDocument.xmlElements[0].xmlElements.add(tag_to_apply, characters.itemByRange(start, end-1));
    
        // shift the end of untagged text
        end += 2;
        if (end >= characters.length) break;
    
        // loop through the text tagged with the skip-tag
        while (characters[end].associatedXMLElements[0].markupTag.name == tag_to_skip) {
            end++;
            if (end >= characters.length) break;
        }
    
        // reset the start and shift the end further
        start = end;
        end += 2;
    }