Replace text between tag only if specified text appears in parent tag



  • I might not have used the correct term tag but this is what I have and what I want to achieve.

    I have an xml file that contains blocks like this:

    <game name="3 in 1 College &amp; Pro Football (Disk 1)" index="true" image="3">
    	<description>3 in 1 College &amp; Pro Football (Disk 1)</description>
    	<manufacturer>Lance Haffner Games</manufacturer>
    	<cloneof/>
    	<crc>C0C68997</crc>
    	<year>1985</year>
    	<genre>Sports/Football</genre>
    	<rating>HSRS - GA (General Audience)</rating>
    	<enabled>Yes</enabled>
    </game>
    <game name="3 in 1 College &amp; Pro Football (Disk 2) (Utilities)" index="" image="">
    	<description>3 in 1 College &amp; Pro Football (Disk 2) (Utilities)</description>
    	<manufacturer>Lance Haffner Games</manufacturer>
    	<cloneof/>
    	<crc>18249FAD</crc>
    	<year>1985</year>
    	<genre>Sports/Football</genre>
    	<rating>HSRS - GA (General Audience)</rating>
    	<enabled>Yes</enabled>
    </game>
    

    What I would like to do is whenever (Disk 2) appears in the game tag, change the enabled tag from Yes to No

    I don’t know how to get the search to treat each set of <game> </game> tags as separate from each other.

    Thank you.



  • Hello, Paul Flint,

    No problem with the right regular expression ! So, the problem can be split in three steps :

    • Go the next name tag, which value contains the string Disk 2

    • Then move, downwards, to the enabled tag of the current game node, in order to catch its Yes value

    • Change that value of the enabled tag, from Yes to No

    The first two steps can be achieved with a search regular expression and the third step with the replacement regular expression !

    So, follow these few steps, below :

    • First, move back to the very beginning of your XML file ( Ctrl + Home )

    • Open the Replace dialog ( Ctrl + H )

    • Select the Regular expression search mode

    • Fill up the two fields Find what: and Replace with:, with the expressions, below :

    SEARCH ((?-s)<game.+Disk 2(?s).+?)Yes(?=</enabled>)

    REPLACE \1No

    • Click on the Replace all button

    Et voilà !

    NOTES :

    • The part (?-s)<game.+Disk 2 looks for the string <game, followed by any, NON-empty, range of standard characters ( due to the (?-s) modifier ), ending with the string Disk 2

    • The part (?s).+?, then, looks for the shortest range of ANY character ( standard or EOL ) ( due to the (?s) modifier )…, till a first string Yes. Note that this range of characters will always be a multi-lines block !

    • The part Yes(?=</enabled>), finally, searches for the string Yes, but ONLY IF this string is followed by the expression </enabled>. If you’re sure that, nowhere else, the Yes string may occur, the positive look-around (?=</enabled>) is not needed !

    • As two parentheses surround the regex expression (?-s)<game.+Disk 2(?s).+? , that means that all text between <game name and <enabled>, just before the string Yes, is stored as group 1

    • In replacement, all that text is just rewritten, due to \1 , and the matched Yes value is, simply, changed into the No value

    Remarks :

    • I suppose that your search is case SENSITIVE. If, for instance, the string disk 2 and/or the value yes may occur, just add the (?i), at beginning of the present search regex, as below, to force the regex engine to perform the search in an INSENSITIVE way :

    (?i)((?-s)<game.+Disk 2(?s).+?)Yes(?=</enabled>)

    • Note, also, that the different in-line modifiers, in regexes, have higher priority than their associate options, in the Find dialog. So, for instance :

      • The regex (?i)AbC would look for the string abc, in ANY case, even if you, previously, checked the Match case option

      • The regex (?-s)A.+Z would look for the longest one-line string , beginning with letter A and ending with letter Z, even if you, previously, checked the . matches newline option

    • An other form of that S/R, using the \K syntax, in the search regex, is :

    SEARCH (?-s)<game.+Disk 2(?s).+?\KYes(?=</enabled>)

    REPLACE No

      • Like above, the regex engine matches from the string <game… ( which contains the Disk 2 string ), till the string <enabled>, but, when meeting the \K form, forgets this match and resets the character position of search to the location just before the Yes value

      • Therefore, it just matches the string Yes, ONLY IF followed by the string </enabled> and changes it with the No value

      • IMPORTANT : Due to the \K syntax, you cannot do replacement step by step, with the Replace button. You must use, EXCLUSIVELY, the Replace All button !

    Best Regards,

    guy038



  • Thank you for your help.


Log in to reply