IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

XSL/XSLT/XPATH XML Discussion :

Comparer des chaînes de caractères et ajouter un élément à partir du contenu d'un autre élément


Sujet :

XSL/XSLT/XPATH XML

  1. #1
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Juillet 2017
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2017
    Messages : 26
    Points : 14
    Points
    14
    Par défaut Comparer des chaînes de caractères et ajouter un élément à partir du contenu d'un autre élément
    Bonjour à tous,

    Avant de vous exposer mon problème, voici un échantillon de mon fichier :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    <DICTIONNAIRE departement="Aisne" dep="02">
     
        <article id="DT02-00001" pg="1">
            <vedette>
                <pg>1</pg>
                <sm>Abancourt,</sm>
            </vedette>
            <definition>
                <typologie>fief</typologie>, <localisation>commune de <commune precision="certain">Brenelle</commune>
                </localisation>*; <typologie>vassal</typologie> de <localisation>Pontarcy</localisation>.
            </definition>
        </article>
     
        <article type="commune" id="DT02-00830" pg="39">
            <vedette>
                <sm>Brenelle,</sm>
            </vedette>
            <definition>
                <localisation>canton de Braine</localisation>.
            </definition>
            <insee>02120</insee>
        </article>
     
        <article id="DT02-00003" pg="1">
            <vedette>
                <sm>Abbaye (L’),</sm>
            </vedette>
            <definition>
                <typologie>ferme et moulin à eau</typologie>, <localisation>commune de <commune precision="certain">Bucilly</commune>
                </localisation>.
            </definition>
        </article>
     
        <article type="commune" id="DT02-00926" pg="43">
            <vedette>
                <sm>Bucilly,</sm>
            </vedette>
            <definition>
                <localisation>canton d’Hirson</localisation>.
            </definition>
            <insee>02131</insee>
        </article>
     
    <article id="DT02-02196" pg="109">
          <vedette>
             <sm>Ferrières,</sm>
          </vedette>
          <definition>
             <typologie>ferme</typologie>, <localisation>commune de <commune precision="certain">la Ferté-Chevresis</commune>
             </localisation>.</definition>
    </article>
     
    <article type="commune" id="DT02-02197" pg="109">
          <vedette>
             <sm>Ferté-Chevresis (La),</sm>
          </vedette>
          <definition>
             <localisation>canton de Ribemont</localisation>.
          </definition>
          <insee>02306</insee>
    </article>
     
    </DICTIONNAIRE>
    Dans mon fichier, chaque article de @type "commune" a un code INSEE placé dans l'élément <insee>.
    Les articles concernant des fermes, hameaux, moulins, etc., se trouvant dans une commune n'ont quant à eux pas de code INSEE, et je souhaite leur attribuer celui de leur commune de rattachement, que j'ai identifiée grâce à l'élément <commune> dans <localisation>.
    Pour ce faire, il faut que je compare le contenu de mes éléments <commune> avec celui de tous les vedette/sm de mon fichier (sachant que le nom des communes n'est pas toujours écrit de la même manière dans l'un et dans l'autre comme c'est le cas pour la Ferté-Chèvresis dans cet exemple), et ainsi récupérer le code INSEE pour le mettre dans un élément <insee_commune>.

    J'ai essayé d'écrire une XSLT mais je n'ai pas réussi...

    Voilà ce que j'ai fait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
     
        <xsl:output method="xml" indent="yes"/>
     
        <xsl:template match="node() | @*">
            <!-- Copie à l'identique du fichier XML -->
            <xsl:copy>
                <xsl:apply-templates select="node() | @*"/>
            </xsl:copy>
        </xsl:template>
     
        <xsl:template match="article[not(@type)]">
            <xsl:copy>
                <xsl:apply-templates select="node() | @*"/>
                <xsl:if test="contains(DICTIONNAIRE/article/vedette/sm[1], definition/localisation[1]/commune)">
                    <xsl:element name="insee_commune">
                        <xsl:value-of select="DICTIONNAIRE/article/insee"/>
                    </xsl:element>
                </xsl:if>
            </xsl:copy>
        </xsl:template> 
     
    </xsl:stylesheet>

    J'ai également tenté cela :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">
     
        <xsl:output method="xml" indent="yes"/>
     
        <xsl:template match="node() | @*">
            <!-- Copie à l'identique du fichier XML -->
            <xsl:copy>
                <xsl:apply-templates select="node() | @*"/>
            </xsl:copy>
        </xsl:template>
     
        <xsl:template match="DICTIONNAIRE">
            <xsl:copy>
                <xsl:apply-templates select="node() | @*"/>
                <xsl:if test="contains(../vedette/sm[1], definition/localisation[1]/commune)">
                    <xsl:for-each select="article[not(@type)]">
                        <xsl:element name="insee_commune">
                            <xsl:value-of select="article/insee"/>
                        </xsl:element>
                    </xsl:for-each>
                </xsl:if>
            </xsl:copy>
        </xsl:template>
    </xsl:stylesheet>
    Je ne sais plus trop comment faire...
    Pouvez-vous m'aider ?
    Merci !

  2. #2
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Juillet 2017
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2017
    Messages : 26
    Points : 14
    Points
    14
    Par défaut
    Est-ce que quelqu'un aurait une idée qui pourrait m'aider ?

  3. #3
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Je veux dire, ton problème c'est qu'un e avec accent c'est pas la même chose qu'un e sans accent. Donc bon ben 'faut convertir tes chaînes en une sorte de version canonique de manière d'écrire un nom de ville.

    De toute façon je te l'ai déjà dit, ce que tu fais là c'est pas transformer des données, c'est ajouter des nouvelles données. Un ordinateur c'est pas fait pour ça. C'est pour ce genre de travail qu'on a des humains, il faut bien que les sacs à viande servent à quelque chose.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  4. #4
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Juillet 2017
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2017
    Messages : 26
    Points : 14
    Points
    14
    Par défaut
    Oui c'est justement mon but d'ajouter de la donnée pour enrichir mes fichiers, mais je veux pouvoir l'automatiser car j'ai de nombreux fichiers, qui sont eux-mêmes très lourds. Si je pouvais le faire manuellement, je le ferais, ce serait beaucoup plus simple, mais ce n'est pas possible.
    Là ce ne sont pas tellement les accents qui me posent problème, c'est plutôt le fait que les mots ne soient pas écrits dans le même ordre dans les deux endroits que je souhaite comparer (par exemple "Ferté-Chevresis (La)" et "la Ferté-Chevresis").
    Et je n'arrive pas à écrire ma règle XSL pour que ça fonctionne.

  5. #5
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Commence déjà par te demander comment tu expliquerais à un enfant de 7 ans que ces deux villes qui ne s'écrivent pas pareil sont censées être les mêmes, parce qu'en changeant ceci ou cela on finit par avoir la même chose.
    Si tu ne peux pas faire ça, tu es pas prête de pouvoir le faire avec un ordinateur.

    A part ça, c'est une chose de vouloir faire de la création de données automatique avec un ordinateur, mais dans ce cas il vaut mieux utiliser un langage de programmation pour décrire les données avec lesquelles on travaille. Un langage de transformation ça ne va pas t'aider.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  6. #6
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Juillet 2017
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2017
    Messages : 26
    Points : 14
    Points
    14
    Par défaut
    Quel langage de programmation je peux utiliser pour faire ça alors ?

  7. #7
    Membre émérite Avatar de tsuji
    Inscrit en
    Octobre 2011
    Messages
    1 558
    Détails du profil
    Informations forums :
    Inscription : Octobre 2011
    Messages : 1 558
    Points : 2 736
    Points
    2 736
    Par défaut
    Ce qu'on peut se douter c'est pourquoi on choisit volontairement de mettre les données tout mêlé plutôt que les données nettes: il n'y a pas de raison de se fabriquer des problèmes pour soi-même... Avec sm, pourquoi <sm>Bucilly,</sm> plutôt que <sm>Bucilly</sm> ? Pour la Ferté-Chevresis et Ferté-Chevresis (La), même c'est très problèmatique de faire matcher par la fonction contains(), on peut accorder un oeil plus sympathique puisque dans le réel, tout le monde ne accorde pas à tout le monde ! C'est dommage mais c'est comme ça.

    Quel langage de programmation je peux utiliser pour faire ça alors ?
    En xslt 2.0 on a déjà beaucoup enrichi quant à la traitement des textes et de les faire analyser. On peut le faire avec xslt 2.0. Mais comme le problème se pose tellement capricieux et les données se rendent tellement librement sans être guidé par des principes directeurs, une solution, parmi d'autre, pourrait paraître excessivement arbitraire et elle ne serrait pas parue robuste, du tout. L'ingrédient central est de trouver un moyen de débarrasser des bruits dans chacune des données - et c'est pénible. Mais, si je puis dire, on peut se tirer une bonne leçon de xslt 2.0 tout de même - et c'est l'essentiel de ce genre d'exercice.

    Je peux vous donner une solution en employant des outils disponible en 2.0 plus avancé; si vous ne comprenez pas tout de suite, je ne peux rien - il vous faut remplaçer des lacunes, syntaxe et raisonnement, vous-même en étudiant la téchnologie lui-même par des tutoriels et articles...

    Code xslt2 : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema" 
        xmlns:udf="urn:tsuji:dvp"
        exclude-result-prefixes="xs udf">
     
    <xsl:output method="xml" indent="yes"/>
     
    <xsl:variable name="ssm_raw" as="xs:string*">
        <xsl:sequence select="/DICTIONNAIRE/article[insee]/vedette/sm/text()" />
    </xsl:variable>
     
    <xsl:variable name="ssm" as="xs:string*">
        <xsl:sequence select="udf:stripping(/DICTIONNAIRE/article[insee]/vedette/sm/text())" />
    </xsl:variable>
     
    <xsl:template match="*|@*|text()">
        <xsl:copy>
            <xsl:apply-templates select="*|@*|text()"/>
        </xsl:copy>
    </xsl:template>
     
    <xsl:template match="article[not(@type)]">
        <xsl:copy>
            <xsl:apply-templates select="*|@*|text()"/>
            <xsl:if test="some $sm in $ssm satisfies contains($sm, udf:stripping(current()/definition/localisation/commune/text()))">
                <xsl:element name="insee_commune">
                    <xsl:value-of select="$ssm_raw[udf:index-of($ssm, udf:stripping(current()/definition/localisation/commune/text()))]" />
                </xsl:element>
            </xsl:if>
        </xsl:copy>
    </xsl:template> 
     
    <xsl:function name="udf:index-of" as="xs:integer*">
        <xsl:param name="sseq" as="xs:string*" />
        <xsl:param name="s" as="xs:string" />
     
        <xsl:for-each select="$sseq">
            <xsl:if test="contains(., $s)">
                <xsl:sequence select="position()" />
            </xsl:if>
        </xsl:for-each>
     
    </xsl:function>
     
    <xsl:function name="udf:stripping" as="xs:string*">
        <xsl:param name="sseq" as="xs:string*" />
     
    <xsl:for-each select="$sseq">
        <xsl:variable name="s" select="." />
        <xsl:variable name="s1" select="replace($s, ',|\.', ' ')" />
        <xsl:variable name="s2" select="replace($s1, '(^|\s+)le(\s+|$)|(^|\s+)\(le\)(\s+|$)l''', ' ', 'i')" />
        <xsl:variable name="s3" select="replace($s2, '(^|\s+)la(\s+|$)|(^|\s+)\(la\)(\s+|$)', ' ', 'i')" />
        <xsl:sequence select="normalize-space($s3)" />
    </xsl:for-each>
     
    </xsl:function>
    </xsl:stylesheet>

    Pour éviter des remarques inutiles, je dis plutôt tout de suite que je n'ai pas essayé de faire le code le plus raccouci possible en sacrificiant lisibilité et puis que la pièce central udf:stripping se prête dans cette forme à élaborer si les données de sm et commune sont mis en place avec des principes rigoreux plutôt, il me semble, que alléatoires. A ce moment, la fonction essais de traiter des particules qui semblent des bruits : la virgule, les articles le, la, Le, La, (le), (la), (Le), (La), ... C'est tellement arbitraire, oui, et qu'on ne me donne une leçon superflue de ça, je sais très bien ces métiers.

  8. #8
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Juillet 2017
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2017
    Messages : 26
    Points : 14
    Points
    14
    Par défaut
    Bonjour,

    Merci beaucoup pour votre aide !!

    Ça fonctionne bien, en revanche tous mes éléments <localisation> ne comportent pas systématiquement l'élément <commune>, et cela pose problème pour
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <xsl:value-of select="$ssm_raw[udf:index-of($ssm, udf:stripping(current()/definition/localisation/commune/text()))]" />
    car udf:index-of n'autorise pas que son deuxième argument soit vide...

  9. #9
    Membre émérite Avatar de tsuji
    Inscrit en
    Octobre 2011
    Messages
    1 558
    Détails du profil
    Informations forums :
    Inscription : Octobre 2011
    Messages : 1 558
    Points : 2 736
    Points
    2 736
    Par défaut
    On peut elaborer le conditionnel pour s'accommoder pour les cas où la 'definition' puisse ne pas avoir 'localisation' comme enfant et puis la 'localisation' puisse ne pas avoir 'commune' comme enfant... comme ça.
    Code xslt : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
            <!--
            <xsl:if test="some $sm in $ssm satisfies contains($sm, udf:stripping(current()/definition/localisation/commune/text()))">
            -->
            <xsl:if test="current()/definition[localisation]
                and
                current()/definition/localisation[commune]
                and
               (some $sm in $ssm satisfies contains($sm, udf:stripping(current()/definition/localisation/commune/text())))
            ">
    J'avais mis current() là où on peut l'épargner tout à fait; mais ces choses deviennent difficile à lire au fur et à mesure et c'est pour ça j'avais l'y mis.

    Les regex's dans la fonction udf:stripping contienent l'erreur dans la partie traitant l' et aussi je pense je devrais regrouper les composants des ou's (|) pour faciliter à lire, voici une version corrigée. Prenez attention s'il vous plaît.
    Code xslt : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <xsl:function name="udf:stripping" as="xs:string*">
        <xsl:param name="sseq" as="xs:string*" />
     
        <xsl:for-each select="$sseq">
            <xsl:variable name="s" select="." />
            <xsl:variable name="s1" select="replace($s, ',|\.', ' ')" />
            <xsl:variable name="s2" select="replace($s1, '((^|\s+)le(\s+|$))|((^|\s+)\(le\)(\s+|$))|((^|\s+)l'')', ' ', 'i')" />
            <xsl:variable name="s3" select="replace($s2, '((^|\s+)la(\s+|$))|((^|\s+)\(la\)(\s+|$))', ' ', 'i')" />
            <xsl:sequence select="normalize-space($s3)" />
        </xsl:for-each>
     
    </xsl:function>

  10. #10
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Juillet 2017
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2017
    Messages : 26
    Points : 14
    Points
    14
    Par défaut
    D'accord merci

    Un autre problème se pose lorsque j'effectue la transformation : j'ai l'erreur suivante :

    "Effective boolean value is not defined for a sequence of two or more items starting with a numeric value"

    Qu'est-ce que cela signifie ?

  11. #11
    Membre émérite Avatar de tsuji
    Inscrit en
    Octobre 2011
    Messages
    1 558
    Détails du profil
    Informations forums :
    Inscription : Octobre 2011
    Messages : 1 558
    Points : 2 736
    Points
    2 736
    Par défaut
    Cela semble suggérer que 'definition' ou plus vraisemblablement 'location' ou 'commune' ne soit pas unique... dans ces cas, ils peuvent poser de problème plus loin même cette erreur trouvant ne bonne résolution.

    On peut utiliser la fonction exists() pour éviter les cas ou le teste retourne plusieurs au lieu qu'un singleton comme ça.
    Code xslt : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
            <xsl:if test="exists(current()/definition[localisation])
                and
                exists(current()/definition/localisation[commune])
                and
               (some $sm in $ssm satisfies contains($sm, udf:stripping(current()/definition/localisation/commune/text())))
            ">

  12. #12
    Membre à l'essai
    Femme Profil pro
    Étudiant
    Inscrit en
    Juillet 2017
    Messages
    26
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2017
    Messages : 26
    Points : 14
    Points
    14
    Par défaut
    D'accord merci je vais tester ça

Discussions similaires

  1. Réponses: 9
    Dernier message: 09/11/2015, 13h14
  2. Comparer des chaînes de caractères
    Par aurelie689 dans le forum Débuter avec Java
    Réponses: 1
    Dernier message: 02/05/2009, 13h22
  3. Problème sur des chaînes de caractères
    Par Anonymous dans le forum Access
    Réponses: 9
    Dernier message: 16/09/2005, 08h21
  4. Passage des chaînes de caractères à une application CGI
    Par Thom@s dans le forum Composants VCL
    Réponses: 10
    Dernier message: 03/12/2004, 00h13

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo