2012-03-27 10 views
2

Versionen von XMLStarlet in aktuellen Linux-Distributionen haben eine Grenze von 128 Operationen pro xmlstarlet ed Aufruf, und Alle Versionen sind durch die maximale Befehlszeilenlänge des Betriebssystems begrenzt. Wie kann das umgangen werden?Umgang mit langen Bearbeitungslisten in XMLStarlet

+0

Ist diese Grenze ein Problem für Sie, in der Praxis? – npostavs

+0

@npostavs Ja, ist es. In meiner Antwort zu http://stackoverflow.com/questions/9880808/shell-script-to-parse-csv-to-an-xml-query/9882015 finden Sie ein Beispiel für einen Fall, in dem mehr als a Handvoll Eingabezeilen. Ich habe auch dieses Problem im kommerziellen, Produktionscode getroffen (obwohl das spezifische Beispiel später überarbeitet wurde, um die relevante Verarbeitung in XQuery statt bash + xmlstarlet zu machen). –

Antwort

3

Die folgenden Pausen lange xmlstarlet bearbeiten Listen in eine Pipeline von kürzeren Operationen:

xmlstarlet_max_commands=100 # max per instance; see http://sourceforge.net/tracker/?func=detail&aid=3488240&group_id=66612&atid=515106 
shopt -s extglob # enable +([0-9]) as an equivalent to the regex ^[[:digit:]]+ 

xmlstarlet_ed() { 
    declare -a global_parameters 
    declare -a parameters 
    declare -i num_commands 
    declare -i cmd_len 

    global_parameters=() 
    parameters=() 
    num_commands=0 

    global_parameters_remaining=$1; shift 

    while ((global_parameters_remaining)); do 
    global_parameters+=("$1"); shift 
    ((global_parameters_remaining--)) 
    done 

    while (("$#")) ; do 
    cmd_len=$1; shift 
    if ! [[ $cmd_len = +([0-9]) ]] ; then 
     echo "ERROR: xmlstarlet_ed commands must be prefixed by run length" 
     return 1 
    fi 

    if ((num_commands < xmlstarlet_max_commands)) ; then 
     parameters+=("${@:1:$cmd_len}") 
     num_commands+=1 
     shift $cmd_len 
    else 
     xmlstarlet ed "${#global_parameters[@]}" "${global_parameters[@]}" "${parameters[@]}" \ 
     | xmlstarlet_ed "${#global_parameters[@]}" "${global_parameters[@]}" "$cmd_len" "[email protected]" 
     return 0 
    fi 
    done 

    if ((${#parameters[@]} > 0)) ; then 
    xmlstarlet ed "${global_parameters[@]}" "${parameters[@]}" 
    else 
    cat 
    fi 
} 

Es kann als so aufgerufen werden:

# first list passed is global parameters; first the count, then the values 
# pass only a 0 if no global parameters are desired 
global_parameters=(2 -N "xhtml=http://www.w3.org/1999/xhtml") 

# build up the parameter list as length/command pairs; the lengths are used 
# to determine the potential split points between subprocesses 
parameters=() 
while read; do 
    parameters+=(8 -s /xhtml:html/xhtml:body -t elem -n line -v "$REPLY") 
done 

# ...and actually invoke: 
xmlstarlet_ed "${global_parameters[@]}" "${parameters[@]}" \ 
<<<"<html xmlns='http://www.w3.org/1999/xhtml'><body/></html>" 
+0

+1 Der Unterschied zwischen 'xmlstarlet_ed' und' xmlstarlet ed' wurde beim ersten Lesen nicht bemerkt. Ich habe das Gefühl, dass eine kurze Nachricht, dass "xmlstarlet_ed" eine rekursive Funktion ist, die Lesbarkeit etwas verbessern würde. –