@files = glob "*.xml"; undef $/; for $file (@files) { $indent = 0; open FILE, $file or die "Couldn't open $file for reading: $!"; $_ = readline *FILE; close FILE or die "Couldn't close $file: $!"; # Remove whitespace between > and < if that is the only thing separating # them s/(?<=>)\s+(?=<)//g; # Indent s{ # Capture a tag <$1$2$3>, # a potential closing slash $1 # the contents $2 # a potential closing slash $3 <(/?)([^/>]+)(/?)> # Optional white space \s* # Optional tag. # $4 contains either undef, "<" or " tag. No alteration to indentation. # $1: A closing tag. Drop one indentation level # else: An opening tag. Increase one indentation level $indent += $3 ? 0 : $1 ? -1 : 1; # Put the captured tag back into place "<$1$2$3>" . # Two closing tags in a row. Add a newline and indent the next line ($1 and ($4 eq "", $file or die "Couldn't open $file for writing: $!"; print FILE or die "Couldn't write to $file: $!"; close FILE or die "Couldn't close $file: $!"; } __END__ This is the version I copied and pasted from the working script. Its ugly so I purtied it up and posted the version you see above this text. I'm leaving this ugly version here just in case I introduced some bug I'm not aware of. @files = glob "*.xml"; undef $/; $tag = "<>/"; for $file (@files) { $indent = 0; open FILE, $file; $_ = ; s/(?<=>)\s+(?=<)//g; s(<(/?)([^/>]+)(/?)>\s*(?=(".($1&&($4 eq"$file"; print FILE; }