More About Macro Syntax

Answered by: Dugald Topshee Last Updated: 2008-08-13

=Question by Chris Makler=

OK, I'm in trouble again.

Is there an adjustment to the s -a -m syntax so that it doesn't search within some elements? Because when I run this more than once it finds the ~Arbortext~ within the tag and does it all over again - and since tags can't accept tags, I get lots of nice beeps.

So: I'd like it do this exact thing, but to exclude tags. Any pointers?

One other question: Once it does this, I want it to insert some code at the top of the file. Specifically, before the script runs, the top of the file looks like this

...  mile kilometer ...

I would like to write a line of code that inserts

yard meter

within the tag, as part of this macro. This must be amazingly easy to do, but again, I can't figure out where to look for this. The closest I've found is insert_tag but that doesn't tell me how to tell it to look for the first instance of the element and insert it under there. I tried doing a find-replace (using the very helpful method outlined before), replacing



With

 yard meter

But it told me I was unbalanced, which is undoubtedly true.

Any help? I know this must be a hopelessly newbie question...

Chris

=Dugald Topshee answers=

Hi Chris,

With regards to your first question, I'm afraid there's no "except inside" flag on the substitute command so you can't write a one-line command that will "replace all 'x' with 'y' except when 'x' is inside ". The good news is that you can accomplish this fairly easily by writing a custom ACL function that simply loops through the find command replacing everything. Essentially instead of making all the changes globally, you execute the find command over and over again and each time you check that the text you wanted meets your conditions. To do this, you can rely on the fact that Epic's $status variable gets set to 0 when the find command is successful. It works like this:

function myFindReplace($this,$that, $tag) {  find -nows "$this"; # the -nows keeps the find from continuing when it gets to the end of the file # essential in your case to avoid an infinite loop since the replacement text # sometimes includes the text you are finding while ($main::status == 0) {    if (!oid_xpath_boolean(oid_caret,"ancestor-or-self::$tag")) {      # the found text is not inside our tag # delete the text: delete_mark null; # add our new text inside the tag we want insert("<$tag>$that</$tag>"); }  } }

Once you've created this function (you can actually enter it at the command line, but it's easier to put it into a separate file with an .acl extension and load it into Epic with the source command), you can call it in your macro like this:

myFindReplace("old text", "new text", "Bold")

and it will find all the "old text" and replace it with "new text" inside a <Bold> tag but not if "old text" is already inside a <Bold> tag. Of course you might want to customize it to your particular needs; for instance if you want to specify an attribute you can add it to the insert line or if in every case the text that you are replacing is the same as the original text, then you can replace the delete_mark and insert lines with the insert_tag command to wrap your text in the tag you want to add. It might take a little trial and error to get the exact result you're looking for, but you should be able to adapt this code to your specific needs.

As for your second question, the easiest way to insert a fairly large passage of text and elements in Epic is with the insert function which inserts any text that you want including markup. You just have to put the cursor in the correct location and then use the following ACL:

insert(" yard</term-model>\ meter</term-model> ");

Of course before you call the insert function, you need to make sure that your cursor is in the correct place, but that's not difficult - especially if you want to get to the beginning of the file. Unfortunately I can't give you the exact code to use without knowing a little bit more of your content model, but if is the root element and you want to be just inside the first of that root, then this should do the trick:

xpath_nodeset($nodes,"/lexicons/lexicon[1]"); goto_oid($nodes[1]);

then do your insert.

Obviously you might need to modify this depending on the content model that you have, but there are all kinds of ways to maneuver the cursor in Epic, it shouldn't be hard to find one that's appropriate for your needs.

Cheers,

Dugald

=See Also=


 * See previous article: How does the macro recorder work?