Newer
Older
api-wos / SOAP / WosSearchByDoi.sh
#!/bin/bash


# Initialisation des variables pour les options
programme=$(basename $0)
substitut=$(echo $programme | sed 's/./ /g')
version='1.3.3'
modif='21/02/2022'

function usage
{
echo "Usage : $programme -s sid -d (fichier|-) -r (résultats|-) "
echo "        $substitut [ -p (début:fin|[124]week) ] [ -b [WOS:]base ]* "
echo "        $substitut [ -f champs ]* [ -c cookies ] [ -i ] "
echo "        $programme -h "
}

function aide
{
cat << EOT

Usage
=====
    $programme -s sid -d (fichier|-) -r (résultats|-)
    $substitut [ -p (début:fin|[124]week) ] [ -b [WOS:]base ]*
    $substitut [ -f champs ]* [ -c cookies ] [ -i ]
    $programme -h

Options principales
===================
    -d  indique le nom du fichier avec la liste des DOIs à chercher. Si on
        a un tiret “-” en argument, la liste de DOIs est lue sur l’entrée
        standard
    -h  affiche cette aide
    -p  limite la recherche dans la base de données à la période indiquée
        sous forme aaaa-mm-jj:aaaa-mm-jj (e.g., “2000-01-01:2020-07-31”)
        ou sous forme “1week”, “2week” ou “4week”
    -r  indique le nom du fichier résultat (pour la sortie standard, utiliser
        le tiret “-” comme argument de l’option)
    -s  indique le jeton d’authentification “SID” obtenu avec le programme
        d‘authentification à l‘API WoS

Autres options
==============
    -b  limite la recherche à une ou plusieurs bases (e.g. “WOS:SCI”).
        Cette option est répétitive et “WOS:” est facultatif (par défaut,
        la recherche se fait sur l’ensemble du WoS)
    -c  indique le nom du fichier qui recevra les cookies (“cookies.txt”
        par défaut)
    -f  limite les champs présents dans les notices téléchargées. Cette
        option est répétitive (par défaut, tous les champs sont présents)
    -i  ajoute dans la réponse de l’API la liste des identifiants WoS des
        notices retournées à chaque itération


EOT

exit 0
}

function nettoie
{
if [[ -f search$$.xml ]]
then
    rm -f search$$.xml
fi
}

# Déclaration explicite du tableau “bases”
declare -a bases
declare -a champs

# Options
while getopts b:c:d:f:hip:r:s: i
    do
    case $i in
        b) bases+=($OPTARG);;
        c) cookie=$OPTARG;;
        d) dois=$OPTARG;;
        f) champs+=($OPTARG);;
        h) aide;;
        i) recid=1;;
        p) span=$OPTARG;;
        r) sortie=$OPTARG;;
        s) sid=$OPTARG;;
        \?) echo  >&2
            usage >&2
            exit 1;;
    esac
    done

# Vérification des options
if [[ -z $sid || -z $dois || -z $sortie ]]
then
    echo "Erreur : option(s) manquante(s)" >&2
    echo "" >&2
    usage >&2
    echo ""
    exit 2
fi

if [[ $dois = '-' ]] 
then
    dois='/dev/fd/0'
fi

if [[ $sortie = '-' ]] 
then
    sortie='/dev/fd/1'
fi

if [[ -z $cookie ]]
then
    cookie='cookies.txt'
fi

# Vérification de la présence des programmes
# “curl” et “xmllint”
for i in curl xmllint
do
    prog=$(which $i 2> /dev/null)
    if [[ -z $prog ]]
    then
        echo "" >&2
        echo "Erreur : programme “$i” introuvable. Vérifier \$PATH." >&2
        echo "" >&2
        exit 3
    fi
done

# Génération d’une liste de bases en XML
# à partir de l’option “-b”
# valeurs possibles : SCI, SSCI, AHCI, ISTP, ISSHP, IC, CCR, BSCI, BHCI et ESCI
declare -a xml1

if [[ ${#bases[@]} -gt 0 ]]
then
    for i in ${bases[@]}
    do
    if [[ $i =~ ^[A-Z]+:[A-Z]+$ ]]
    then
        coll=${i%:*}
        edit=${i#*:}
    else
        coll='WOS'
        edit=$i
    fi
    xml1+=("            <editions>")
    xml1+=("               <collection>$coll</collection>")
    xml1+=("               <edition>$edit</edition>")
    xml1+=("            </editions>")
    done
fi

# Génération d’une période en XML avec l’option “-p”
declare -a xml2

if [[ -n $span ]]
then
    regex="[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])"
    if [[ $span =~ ^$regex:$regex$ ]]
    then
        begin=${span%:*}
        end=${span#*:}
        # Vérification de la validité de chaque date
        for i in $begin $end
        do
            day=$(date -d $i 2> /dev/null)
            if [[ -z $day ]]
            then
                echo ""
                echo "Erreur : date “$i” invalide" >&2
                nettoie
                exit 4
            fi
        done
        xml2+=("            <timeSpan>")
        xml2+=("               <begin>$begin</begin>")
        xml2+=("               <end>$end</end>")
        xml2+=("            </timeSpan>")
    elif [[ $span =~ ^[124]week$ ]]
    then
        xml2=("            <symbolicTimeSpan>$span</symbolicTimeSpan>")
    else
        echo ""
        echo "Erreur : argument incorrect pour l’option “-p”" >&2
        nettoie
        exit 4
    fi
fi

# Génération d’une période en XML avec l’option “-f”
#    Valeurs possibles : 
#    UID, pub_info, names, full_name, titles, contributor, language, doctypes, 
#    conf_title, conf_date, conf_host, conf_locations, sponsors, keywords,
#    keywords_plus, abstract, addresses, organizations, reprint_contact,
#    email_addr, grant, fund_text, refs, address_spec, headings, subjects, 
#    identifiers, page, book_chapters et ids
declare -a xml3
if [[ ${#champs[@]} -gt 0 ]]
then
    for item in ${champs[@]}
    do
        while [[ -n $item ]]
        do
            deb=${item%%,*}
            fin=${item#*,}
        xml3+=("              <fieldName>$deb</fieldName>")
        if [[ $deb = $fin ]]
        then
            item=""
        else
            item=$fin
        fi
        done
    done
fi

# Variables diverses
out='WosApiOut.txt'
err='WosApiErr.txt'
rec=0
max=0
total=0

# Fonction de génération du fichier SOAP, d’interrogation
# de l’API et de test de la réponse
function requete
{
local ns='FullRecord'

end=$(( $3 + $2 - 1 ))
printf " ->  %d - %d  " $3 $end >&2

# Génération du fichier SOAP
# 1) entête + requête
cat << EOT > search$$.xml
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
   xmlns:woksearch="http://woksearch.v3.wokmws.thomsonreuters.com">
   <soapenv:Header/>
   <soapenv:Body>
      <woksearch:search>
         <queryParameters>
            <databaseId>WOS</databaseId>
            <userQuery>DO=($1)</userQuery>
EOT

# 2) cas des bases WoS
if [[ ${#xml1[@]} -gt 0 ]]
then
    for i in "${xml1[@]}"
    do
        echo "$i" >> search$$.xml
    done
fi

# 3) cas de la période
if [[ ${#xml2[@]} -gt 0 ]]
then
    for i in "${xml2[@]}"
    do
        echo "$i" >> search$$.xml
    done
fi

# 4) Nb de notices
cat << EOT >> search$$.xml
            <queryLanguage>en</queryLanguage>
         </queryParameters>
         <retrieveParameters>
            <firstRecord>1</firstRecord>
            <count>$2</count>
EOT

# 5) liste des champs affichés (option “-f”)

if [[ ${#xml3[@]} -gt 0 ]]
then
    ns='Fields'
    echo "            <viewField>" >> search$$.xml
    echo "              <collectionName>WOS</collectionName>" >> search$$.xml
    for i in "${xml3[@]}"
    do
        echo "$i" >> search$$.xml
    done
    echo "            </viewField>" >> search$$.xml
fi

# 6) Affichage des identifiants de notices retournées
if [[ $recid -gt 0 ]]
then
    echo "            <option>" >> search$$.xml
    echo "               <key>RecordIDs</key>" >> search$$.xml
    echo "               <value>On</value>" >> search$$.xml
    echo "            </option>" >> search$$.xml
fi

# 7) fin des paramètres
cat << EOT >> search$$.xml
            <option>
               <key>targetNamespace</key>
               <value>http://scientific.thomsonreuters.com/schema/wok5.4/public/$ns</value>
            </option>
        </retrieveParameters>
      </woksearch:search>
   </soapenv:Body>
</soapenv:Envelope>
EOT

# Interrogation de l’API WoS
curl -X POST -d @search$$.xml -b $cookie -c $cookie -v 'http://search.webofknowledge.com/esti/wokmws/ws/WokSearch?wsdl' \
     -H "Cookie: SID=$sid" 2> $err | xmllint -format - > $out

# Test de la réponse
qid=$(perl -ne 'print "$1" if m|<queryId>(.+?)</queryId>|;' $out)
if [[ -n $qid ]]
then
    rec=$(perl -ne 'print "$1" if m|<recordsFound>(.+?)</recordsFound>|;' $out)
    max=$(perl -ne 'print "$1" if m|<recordsSearched>(.+?)</recordsSearched>|;' $out)
    total=$(( $total + $rec ))
    cat $out >> $sortie
else
    msg=$(perl -ne 'print "$1" if m|<faultstring>(.+?)</faultstring>|;' $out)
    if [[ -n $msg ]]
    then
        echo " "
        echo "Erreur : $msg "
        echo " "
    else
        echo " "
        echo "Erreur indéterminée. "
        echo "Voir fichier “$err”. "
        echo " "
    fi

    nettoie
    exit 5
fi

printf "                                                \r" >&2
}

# Nettoyage en cas d’arrêt prématuré
trap nettoie HUP INT QUIT TERM

# Itéraion sur la liste des DOIs
nb=0
offset=1

    while read x
    do
        nb=$(( $nb + 1 ))

        if [[ $nb -eq 1 ]]
        then
            liste="$x"
        else
            liste="$liste OR $x"
        fi

        if [[ $nb -eq 100 ]]
        then
            requete "$liste" "$nb" "$offset"
            offset=$(( $offset + $nb ))
            liste=""
            nb=0
        fi
    done < $dois
# fi

if [[ $nb -gt 0 ]]
then
    requete "$liste" "$nb" "$offset"
fi

nettoie

nb=$(( $offset + $nb - 1 ))

printf "                                                \r" >&2
(echo " " >&2
 echo "Nombre de DOIs cherchés : $nb" >&2
 echo "Nombre de notices trouvées : $total / $max notices") |
    perl -pe '1 while(s/(\d)(\d\d\d)\b/$1 $2/o);' >&2


exit 0