General XMetaL Discussion

XMetaL Community Forum General XMetaL Discussion Makro Search Entity and Replace it

  • ndudek

    Makro Search Entity and Replace it

    Participants 21
    Replies 22
    Last Activity 9 years, 3 months ago

    Hi,

    I'm looking for a way to find an Entity and Replace it with text. The XMetaL Find & Replace Dialog offers a way to do it but i would like to use it in a macro. I tried to access these search options but I can't find them. So is there a way to find entities and replace them?

    I know there is a workaround (switching views and replace the entities in plain text view) but maybe there is a better way to do it?

    Reply

    Derek Read

    Reply to: Makro Search Entity and Replace it

    There is no API dedicated to this type of thing, but I think you can probably do what you want with a combination of other APIs.

    With the following document open in XMetaL Author (Enterprise or Essential)…
    [code=Journalist demo document]
     
     
     
    ]>

      <?xm-replace_text {Article Title}?>
     
    a&old;b&somethingelse;c&old;d a&somethingelse;b&test;c&somethingelse;d 
    December 19, 2013 2:21:52 PM

    [/code]

    …running the following script will replace all the “old” entity references with references to the “new” entity.
    [code=sample script]//XMetaL Script Language JScript:
    if((ActiveDocument.ViewType == sqViewNormal)||(ActiveDocument.ViewType == sqViewTagsOn)) {
    var entRefToReplace = “old”;
    var entRefToInsert = “new”; //this entity ref must be declared
    var rng1 = ActiveDocument.Range;
    rng1.MoveToDocumentStart();
    var rng2 = rng1.Duplicate;
    rng1.GotoNext(0);
    while(rng2.IsLessThan(rng1)) {
    if(rng2.ContainerName == “.ENTREF”) {
    if(rng2.ContainerNode.nodeName == entRefToReplace) {
    Application.Alert(“found one: ” + rng2.ContainerNode.nodeName);
    rng2.SelectElement();
    rng2.Delete();
    rng2.InsertEntity(entRefToInsert);
    }
    }
    rng2.GotoNext(0);
    rng1.GotoNext(0);
    }
    }[/code]

    Reply

    ndudek

    Reply to: Makro Search Entity and Replace it

    Hi Derek,

    thanks for your input. I'm close to the final solution but it doesn't work.

    It seems like there is something wrong with the “IsLessThan” Method. I'm working in VBScript but that shouldn't be the problem.
    Following Document:
    [code]




    ]>

      t est

    [/code]

    Following Macro:
    [code]
    ActiveDocument.Host.DisplayAlerts = 0
    Dim entRefToReplace
    entRefToReplace = “nbsp”
    Dim textToInsert
    textToInsert = ” “
    Dim rng1
    Set rng1 = ActiveDocument.Range
    rng1.HomeKey
    Dim rng2
    Set rng2 = rng1.Duplicate
    rng1.GotoNext(0)
    while rng2.IsLessThan(rng1)
    if rng2.ContainerName = “.ENTREF” Then
    if rng2.ContainerNode.nodeName = entRefToReplace Then
    rng2.SelectElement
    rng2.Delete
    rng2.Text = textToInsert
    End if
    End if
    rng2.GotoNext(0)
    rng1.GotoNext(0)
    wend
    ActiveDocument.Host.DisplayAlerts = -1
    [/code]

    It just replace nothing here. Maybe because there is no Element after the nbsp?

    Reply

    Derek Read

    Reply to: Makro Search Entity and Replace it

    Might be a logic problem in my code. I'd suggest debugging and stepping through your script step by step to see if you can find the problem with the logic.

    To start a script debugger with VBScript add the keyword “stop” to the start of your script (you need to have a script debugger installed of course). If you don't have something like Visual Studio installed you can use the free script debugger Microsoft provides. I think this is the current link to it: http://www.microsoft.com/en-us/download/details.aspx?id=22185

    Reply

    Derek Read

    Reply to: Makro Search Entity and Replace it

    Is the ultimate goal for this script to replace only nbsp with a normal space?
    If so perhaps we could simplify it a lot by simply doing a text replacement on the entire document as a string.

    I'm suggesting this because my brain is stuck figuring out the logic from my original script. I see why it does not work but not how to fix it. It doesn't work when rng1 cannot go further than the last entity, which is what happens with your example document. GotoNext() is working as designed, but is no good for this usage as far as I can tell. I think MoveRight() might get you closer, but I think that would make the script very slow.

    A script that loads the whole document into a string, replaces all the entities using regular expression matching and then replaces the entire document with the new version might do it. I wonder if that would work for your use case (not sure about your timing or other requirements). The user's current selection will be lost, so I think it only makes sense to do this either as part of something where users are not involved at all, or just after document open.

    I'm much faster at JScript than VBScript so here's a JScript example:

    [code]//XMetaL Script Language JScript:
    var rng = ActiveDocument.Range;
    rng.SelectAll();
    var wholeDocAtRoot = rng.TextWithRM;
    Application.Alert(wholeDocAtRoot);
    var rx = / /g;
    var newDoc = wholeDocAtRoot.replace(rx,” “);
    Application.Alert(newDoc);
    rng.Delete();
    rng.PasteString(newDoc);[/code]

    Reply

    Derek Read

    Reply to: Makro Search Entity and Replace it

    Note that if other entities also need replacement you could obviously just place the replacement portion of this code in a loop.

    Reply

    ndudek

    Reply to: Makro Search Entity and Replace it

    I think the problem with GotoNext is that there is no element after the entity that's why it won't work with the example I posted.
    Replacing the text would help but is there a way to keep the current users selection? That would be the best solution.

    The ultimate goal for the script is to switch between entitys displayed as a container and the character that represents the entity but not displayed in a container.
    I attached a screenshot to give you an example what the script does.

    We have documents that contain the entity and are displayed in these containers. And some of them don't have them which leads to confusion. So the idea is to give the user control whether he want's to have containers or not.

    Reply

    Derek Read

    Reply to: Makro Search Entity and Replace it

    The only way to keep the current selection is to make modifications similar to my first attempt that you used as an example. You are correct in why it is failing. GotoNext isn't able to move anymore and so it ends prematurely in some cases. I'll need to think about that some more, but I hesitate to do so when that might be a waste of effort.

    It sounds like you are trying to recreate existing functionality. Perhaps you are not aware of the feature that shows the entity reference in Tags On view and the entity's expanded text in Normal view? All you need to do is switch views and no changes to the document are actually made in this case (the document is just rendered differently). There is an INI setting to disable this, but it is enabled by default.

    I might not be understanding you though, as I'm not sure what you mean by “container”. I assume you just mean the entity reference, which in your example is the entity reference.

    Reply

    ndudek

    Reply to: Makro Search Entity and Replace it

    The Problem is that the nbsp entity isn't displayed if the xml (plain text) contains the character which is   character.
    I attached you another screenshot, i think we are talking about the same, just to clarify the red underlined entity is the “container”.
    The blue underlined whitespace is the   character which is the nbsp displayed in normal view.

    We are working in Tags on view, always and there are sometimes entitys and sometimes not. To help the users we would like to be able to switch in the tags on view view between displaying entities and displaying the characters.

    Reply

    Derek Read

    Reply to: Makro Search Entity and Replace it

    [I don't see a screenshot here. If you are having difficultly with that perhaps you should open a support case with XMetaL Support so we can discuss via email.]

    It sounds like the issue is really that a no-break space is rendered like a “regular” space (which is normal since they do generally look identical but behave differently). Is your ultimate problem that your authors are unable to figure out which character is which when comparing a space to a no-break space (U+0020 vs U+0160)?

    In your final document (what you need to save to disk) do you need to save the entity or the character to disk?

    If you can avoid the use of entities then other means for identifying no-break spaces might be implemented. If you really need to use entities then I can have a look at these scripts again.

    Reply

    ndudek

    Reply to: Makro Search Entity and Replace it

    Seems like i forgot to attach it.
    So now it is attached.

    Users are unable to difference between normal spaces and non breaking spaces if non breaking spaces are displayed as normal spaces. If they are displayed as entities they can so that is the goal.

    Reply

    Derek Read

    Reply to: Makro Search Entity and Replace it

    After sleeping on this I had a thought. While stepping though this with a debugger I was pretty sure I saw that the last call to  GotoNext() will always get to an entity, even if it is at the end of the document (no more elements to move to). The real issue is that the other call to GotoNext for the other range doesn't move past it so the comparison that gets the while loop to run one more time stops. So, if we just check one last time after the loop to see if we're on an entity then that should fix it I think.

    Here's my original script modified to do that:

    [code]//XMetaL Script Language JScript:
    if((ActiveDocument.ViewType == sqViewNormal)||(ActiveDocument.ViewType == sqViewTagsOn)) {
    var entRefToReplace = “old”;
    var entRefToInsert = “new”; //this entity ref must be declared
    var rng1 = ActiveDocument.Range;
    rng1.MoveToDocumentStart();
    var rng2 = rng1.Duplicate;
    rng1.GotoNext(0);
    while(rng2.IsLessThan(rng1)) {
    if(rng2.ContainerName == “.ENTREF”) {
    if(rng2.ContainerNode.nodeName == entRefToReplace) {
    Application.Alert(“found one: ” + rng2.ContainerNode.nodeName);
    rng2.SelectElement();
    rng2.Delete();
    rng2.InsertEntity(entRefToInsert);
    }
    }
    rng2.GotoNext(0);
    rng1.GotoNext(0);
    }
    //do one final check in case the last thing we ended on was an entity reference
    if(rng2.ContainerName == “.ENTREF”) {
    if(rng2.ContainerNode.nodeName == entRefToReplace) {
    Application.Alert(“found one: ” + rng2.ContainerNode.nodeName);
    rng2.SelectElement();
    rng2.Delete();
    rng2.InsertEntity(entRefToInsert);
    }
    }
    }
    [/code]

    Your's would be something like this then I think:
    [code]Dim entRefToReplace
    entRefToReplace = “nbsp”
    Dim textToInsert
    textToInsert = ” “
    Dim rng1
    Set rng1 = ActiveDocument.Range
    rng1.HomeKey
    Dim rng2
    Set rng2 = rng1.Duplicate
    rng1.GotoNext(0)
    while rng2.IsLessThan(rng1)
    if rng2.ContainerName = “.ENTREF” Then
    if rng2.ContainerNode.nodeName = entRefToReplace Then
    rng2.SelectElement
    rng2.Delete
    rng2.Text = textToInsert
    End if
    End if
    rng2.GotoNext(0)
    rng1.GotoNext(0)
    wend
    'do one final check in case the last thing we ended on was an entity reference
    if rng2.ContainerName = “.ENTREF” Then
    if rng2.ContainerNode.nodeName = entRefToReplace Then
    rng2.SelectElement
    rng2.Delete
    rng2.Text = textToInsert
    End if
    End if[/code]

    Note: Make sure the space in that string is the type you want. It is likely to have been lost between my editor and the editor for the forum and on the way back out.

    Having done that I don't know that this solution using entities is really the best, but I suppose if your authors like it then I should't argue with them.

    Reply

    ndudek

    Reply to: Makro Search Entity and Replace it

    That helped me a lot.
    Sometimes the solution is so easy but you think to comlicated.
    Anyway we now can do what we want so thank you for your assistance.

    Reply

    edporterIII

    Reply to: Makro Search Entity and Replace it

    Is the ultimate goal for this script to replace only nbsp with a normal space?
    If so perhaps we could simplify it a lot by simply doing a text replacement on the entire document as a string.

    I'm suggesting this because my brain is stuck figuring out the logic from my original script. I see why it does not work but not how to fix it. It doesn't work when rng1 cannot go further than the last entity, which is what happens with your example document. GotoNext() is working as designed, but is no good for this usage as far as I can tell. I think MoveRight() might get you closer, but I think that would make the script very slow.

    A script that loads the whole document into a string, replaces all the entities using regular expression matching and then replaces the entire document with the new version might do it. I wonder if that would work for your use case (not sure about your timing or other requirements). The user's current selection will be lost, so I think it only makes sense to do this either as part of something where users are not involved at all, or just after document open.

    I'm much faster at JScript than VBScript so here's a JScript example:

    [code]//XMetaL Script Language JScript:
    var rng = ActiveDocument.Range;
    rng.SelectAll();
    var wholeDocAtRoot = rng.TextWithRM;
    Application.Alert(wholeDocAtRoot);
    var rx = / /g;
    var newDoc = wholeDocAtRoot.replace(rx,” “);
    Application.Alert(newDoc);
    rng.Delete();
    rng.PasteString(newDoc);[/code]

    Sorry to bring this post back from the dead, but your code example works for me. However, it removes all of the track changes PIs on paste.

    Is there any way to search/replace with regular expressions that will preserve the track changes markup?

    Reply

    Derek Read

    Reply to: Makro Search Entity and Replace it

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

Lost Your Password?

Products
Downloads
Support