Últimamente estoy programando scripts en gawk, un lenguaje de scripts bastante potente diseñado para trabajar con ficheros de texto plano. Lo que me ha tenido entretenido los últimos días ha sido una función que dado un texto XML lo devuelva indentado, bonito (pretty) para que se pueda leer con facilidad.
Aquí pongo la función esperando que le pueda resultar útil a alguien y también que, si se encuentran errores me avisen para corregirlos. Pongo los comentarios en inglés porque tenía que ponerlos en inglés en el trabajo, además así se puede aprovechar por más gente.
Los habituales que no se me enfaden, que volveré con temas más asequibles después del puente: Feliz día del trabajador a todos, y buen puente para el que lo tenga.
# This function returns a string formed by "char" "n" times.
function nChars(n,char,
str,i){
str="";
for( i = 0; i < n; i++ ){
str = str char;
}
return( str );
}
# This function chages an xml message to a pretty XML format.
# The "<" and the ">" characters are changed by "####" and "##"
# respectively (Variable openTag and closeTag).
# I assume that these characters sequences won't appear in the
# original message
# The indentation is made using the indentChar variable.
function prettyXML(msg,
indent, charPrev, charNext, replace, indentChar, openTag,
closeTag){
indent = 0;
indentChar = " ";
openTag = "####";
closeTag = "##";
while( match(msg,/>[ \r\t\n]*</ )) {
charPrev = substr( msg, RSTART-1, 1 );
charNext = substr( msg, RSTART+RLENGTH, 1 );
# If the next char after the regular expression is "/"
# it means that the next tag is a closing tag,
# so it's necessary to subtract one from indentation;
# otherwise it's necessary check the previous char before
# to add one indentation, only when the
# previous tag is not a closing tag.
if( charNext == "/" ) {
indent --;
} else {
if( charPrev != "/" \
&& substr(msg, 1, RSTART) !~ openTag "/[^#<]*>$" \
&& substr(msg, 1, RSTART) !~ /<\/[^#<]*>$/ ) {
indent ++;
}
}
replace = closeTag "\n" nChars(indent, indentChar) openTag;
sub( />[ \r\t\n]*<;/, replace, msg )
}
gsub( openTag, "<", msg );
gsub( closeTag, ">", msg );
return ( msg );
}