2017-08-05 2 views
0

Je dois obtenir la valeur de chaque donnée après le dernier deux-points. Par exemple, j'ai ce fichier:Récupère la valeur après chaque dernier deux-points

<Data> 
:20:PmtReferenceID000012 
:21:Not used 
:25: PHMNLBICXXX/Account00010203 
:28c:00001/0001 (The 'c' in :28 can be either in upper or lower case) 

:20:PmtReferenceID000012 
:21:Not used 
:25: PHMNLBICXXX/Account00010203 
:28c:00001/0001 (The 'c' in :28 can be either in upper or lower case) 
</Data> 

je dois stocker la valeur après ': 20:' à <ABCD>, ': 21:' à <EFGH>, ': 25:' à <IJKL> et « : 28c : 'à <MNOP>.

Voici mon XSLT:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions"> 
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
<xsl:template match="@*|node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
</xsl:template> 
<xsl:template match="Data"> 
    <Data> 
     <xsl:variable name="OneLine" select="replace(translate(.,'&#10;', '|'),'&#xD;','')"/> 
     <ABCD> 
      <xsl:value-of select="substring-before(substring-after($OneLine, ':20:'),'|:')"/> 
     </ABCD> 
     <EFGH> 
      <xsl:value-of select="substring-before(substring-after($OneLine, ':21:'),'|:')"/> 
     </EFGH> 
     <IJKL> 
      <xsl:value-of select="substring-before(substring-after($OneLine, ':25:'),'|:')"/> 
     </IJKL> 
     <MNOP> 
      <xsl:value-of select="substring-before(substring-after($OneLine, ':28c:'),'|:')"/> 
     </MNOP> 
    </Data> 
</xsl:template> 

Sortie prévue:

<Data> 
    <ABCD>PmtReferenceID000012</ABCD> 
    <EFGH>Not used</EFGH> 
    <IJKL> PHMNLBICXXX/Account00010203</IJKL> 
    <MNOP>00001/0001</MNOP> 
</Data> 
<Data> 
    <ABCD>PmtReferenceID000012</ABCD> 
    <EFGH>Not used</EFGH> 
    <IJKL> PHMNLBICXXX/Account00010203</IJKL> 
    <MNOP>00001/0001</MNOP> 
</Data> 

Ce que je l'ai dit, je remplace d'abord le retour chariot à la conduite ('|'), donc cela, si je reçois la valeur par exemple le ': 20:', je chercherai le '|' et sous-chaîne la valeur après ': 20:' et avant le '|'. Est-ce qu'il y a un moyen facile d'obtenir la valeur après chaque dernier deux-points parce qu'il y a tellement de clés, si je vais utiliser la méthode que j'ai faite? Je pense à utiliser un index ou une position, et stocker toutes les clés (: 20:,: 21:, 25:,: 28c '), de sorte que si l'enregistrement suivant contient': 21: 'ou': 25 : 'ou': 28c ', il aura la valeur avant cette clé. Mais, je n'ai aucune idée sur comment vais-je faire cela en utilisant xslt.

Vos commentaires sont les bienvenus!

Merci,

+1

RE votre edit: s'il vous plaît expliquer la règle exacte ** ** par lequel les données sont réparties. Y a-t-il un double saut de ligne séparant les blocs, ou autre chose? Et le modèle se répète-t-il vraiment, ou est-ce juste une coïncidence? –

Répondre

0

J'ai écrit cette réponse à votre message original mais n » ai pas Je l'ai posté parce qu'il était essentiellement similaire à celui posté par zx485.

Cependant, je recommande toujours d'utiliser un key pour récupérer le nom d'élément correspondant (et je pense aussi que l'expression rationnelle peut être plus simple et plus robuste).

J'ai ajouté une étape de segmentation des données dans des enveloppes <Data> distinctes sur chaque caractère de saut de ligne double.

XSLT 2,0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<!-- identity transform --> 
<xsl:template match="@*|node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:variable name="map"> 
    <name key="20">ABCD</name> 
    <name key="21">EFGH</name> 
    <name key="25">IJKL</name> 
    <name key="28C">MNOP</name> 
</xsl:variable> 

<xsl:key name="nm" match="name" use="@key" /> 

<xsl:template match="Data"> 
    <xsl:for-each select="tokenize(., '\n\n')"> 
     <Data> 
      <xsl:analyze-string select="." regex="^:([^:]*):(.*)$" flags="m"> 
       <xsl:matching-substring> 
        <xsl:element name="{key('nm', upper-case(regex-group(1)), $map)}"> 
         <xsl:value-of select="regex-group(2)" /> 
        </xsl:element> 
       </xsl:matching-substring> 
      </xsl:analyze-string> 
     </Data> 
    </xsl:for-each> 
</xsl:template> 

</xsl:stylesheet> 

Démo: http://xsltransform.net/ehVYZNm

+0

Merci beaucoup @ michael.hor257k. – user7918368

2

est-il un moyen facile sur Vais-je obtenir la valeur après chaque dernier colon, car il y a tellement de clés [...]

Oui. Vous pouvez utiliser la correspondance RegEx.
Dans le modèle suivant regex-group(2) contient la chaîne après le second/(dernier) deux-points. Et regex-group(1) contient la clé.

<xsl:template match="Data"> 
    <Data> 
     <xsl:analyze-string select="." regex=":([0-9A-Za-z]+):(.*)\n"> 
      <xsl:matching-substring> 
       (<xsl:value-of select="regex-group(1)" /> --- <xsl:value-of select="regex-group(2)" />)<xsl:text>&#xa;</xsl:text> 
      </xsl:matching-substring> 
     </xsl:analyze-string> 
    </Data> 
</xsl:template> 

sortie partielle:

(20 --- PmtReferenceID000012) 
(21 --- Not used) 
(25 --- PHMNLBICXXX/Account00010203) 
(28c --- 00001/0001 (The 'c' in :28 can be either in upper or lower case)) 

Avec que vous pouvez créer un dictionnaire clé/valeur qui crée les balises autour du texte.

Comme ceci:

  • Key: 20, Valeur: ABCD
  • Key: 21, Valeur: EFGH
  • ...

Par exemple, vous pouvez créer une variable à l'intérieur du fichier XSL pour stocker le mappage:

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:fn="http://www.w3.org/2005/xpath-functions" 
    xmlns:map="http://custom.map"> 
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 

    <xsl:variable name="Mapping"> 
    <Map key="20">ABCD</Map> 
    <Map key="21">EFGH</Map> 
    <Map key="25">IJKL</Map> 
    <Map key="28c">MNOP</Map> 
    </xsl:variable> 

    <xsl:template match="@*|node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="Data"> 
    <Data> 
     <xsl:analyze-string select="." regex=":([0-9A-Za-z]+):(.*)\n"> 
      <xsl:matching-substring> 
       <xsl:element name="{$Mapping/Map[@key=regex-group(1)]/text()}"><xsl:value-of select="regex-group(2)" /></xsl:element> 
      </xsl:matching-substring> 
     </xsl:analyze-string> 
    </Data> 
    </xsl:template> 
</xsl:stylesheet> 

sortie complète:

<?xml version="1.0" encoding="UTF-8"?> 
<Data xmlns:xs="http://www.w3.org/2001/XMLSchema" 
     xmlns:fn="http://www.w3.org/2005/xpath-functions" 
     xmlns:map="http://custom.map"> 
    <ABCD>PmtReferenceID000012</ABCD> 
    <EFGH>Not used</EFGH> 
    <IJKL> PHMNLBICXXX/Account00010203</IJKL> 
    <MNOP>00001/0001 (The 'c' in :28 can be either in upper or lower case)</MNOP> 
</Data> 

Ou vous pouvez externaliser littéralement la mise en correspondance et de créer un fichier séparé pour eux ...

+1

C'est XSLT 2.0: vous pouvez utiliser une variable ** et ** une clé. –

+0

@ zx485 - merci pour vos commentaires. Cela fonctionne mais, puis-je savoir comment je ferai l'itération si j'ai plusieurs données dans l'enregistrement de données? J'ai édité mon message l'entrée et la sortie attendue. Merci d'avance. – user7918368

3

Dans XSLT 3.0, vous pouviez écrire des modèles pour les différentes chaînes, par ex.

<?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" 
    xmlns:math="http://www.w3.org/2005/xpath-functions/math" exclude-result-prefixes="xs math" 
    version="3.0"> 

    <xsl:output indent="yes"/> 

    <xsl:template match="Data"> 
     <xsl:copy> 
      <xsl:apply-templates select="tokenize(., '\r?\n')[normalize-space()]"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match=".[. instance of xs:string and matches(., '^:20:')]"> 
     <ABCD> 
      <xsl:value-of select="replace(., '^:20:', '')"/> 
     </ABCD> 
    </xsl:template> 

    <xsl:template match=".[. instance of xs:string and matches(., '^:21:')]"> 
     <EFGH> 
      <xsl:value-of select="replace(., '^:21:', '')"/> 
     </EFGH> 
    </xsl:template> 

    <xsl:template match=".[. instance of xs:string and matches(., '^:25:')]"> 
     <IJKL> 
      <xsl:value-of select="replace(., '^:25:', '')"/> 
     </IJKL> 
    </xsl:template> 

    <xsl:template match=".[. instance of xs:string and matches(., '^:28c:', 'i')]"> 
     <MNOP> 
      <xsl:value-of select="replace(., '^:28c:', '', 'i')"/> 
     </MNOP> 
    </xsl:template>  
</xsl:stylesheet> 

Avec Saxon 9,8 ou Altova XMLSpy/Raptor qui fait le travail et les sorties

<Data> 
    <ABCD>PmtReferenceID000012</ABCD> 
    <EFGH>Not used</EFGH> 
    <IJKL> PHMNLBICXXX/Account00010203</IJKL> 
    <MNOP>00001/0001</MNOP> 
</Data> 

(pour l'entrée

<Data> 
:20:PmtReferenceID000012 
:21:Not used 
:25: PHMNLBICXXX/Account00010203 
:28c:00001/0001 
</Data> 

)

En variante, au lieu de tokenizing et le traitement des chaînes, vous pouvez utiliser la fonction analyze-string et correspondre sur le retourné fn:match éléments:

<?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" 
    xmlns:fn="http://www.w3.org/2005/xpath-functions" 
    xmlns:math="http://www.w3.org/2005/xpath-functions/math" 
    exclude-result-prefixes="xs fn math" 
    version="3.0"> 

    <xsl:output indent="yes"/> 

    <xsl:template match="Data"> 
     <xsl:copy> 
      <xsl:apply-templates select="analyze-string(., '^(:[0-9]+[a-z]*:)(.*)\r?\n', 'im')//fn:match"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="fn:match[fn:group[@nr = 1][. = ':20:']]"> 
     <ABCD> 
      <xsl:value-of select="fn:group[@nr = 2]"/> 
     </ABCD> 
    </xsl:template> 

    <xsl:template match="fn:match[fn:group[@nr = 1][. = ':21:']]"> 
     <EFGH> 
      <xsl:value-of select="fn:group[@nr = 2]"/> 
     </EFGH> 
    </xsl:template> 

    <xsl:template match="fn:match[fn:group[@nr = 1][. = ':25:']]"> 
     <IJKL> 
      <xsl:value-of select="fn:group[@nr = 2]"/> 
     </IJKL> 
    </xsl:template> 

    <xsl:template match="fn:match[fn:group[@nr = 1][matches(., '^:28c:', 'i')]]"> 
     <MNOP> 
      <xsl:value-of select="fn:group[@nr = 2]"/> 
     </MNOP> 
    </xsl:template> 

</xsl:stylesheet> 

Enfin, reprenant l'idée d'un paramètre de carte pour définir les noms d'éléments de la deuxième solution peut être réduite à

<?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" 
    xmlns:fn="http://www.w3.org/2005/xpath-functions" 
    xmlns:math="http://www.w3.org/2005/xpath-functions/math" 
    exclude-result-prefixes="xs fn math" 
    version="3.0"> 

    <xsl:param name="map" as="map(xs:string, xs:string)" 
     select="map { 
        '20' : 'ABCD', 
        '21' : 'EFGH', 
        '25' : 'IJKL', 
        '28c' : 'MNOP' 
       }"/> 

    <xsl:output indent="yes"/> 

    <xsl:template match="Data"> 
     <xsl:copy> 
      <xsl:apply-templates select="analyze-string(., '^(:([0-9]+[a-z]*):)(.*)\r?\n', 'im')//fn:match" mode="wrap"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="match" mode="wrap" xpath-default-namespace="http://www.w3.org/2005/xpath-functions"> 
     <xsl:element name="{$map(lower-case(.//group[@nr = 2]))}"> 
      <xsl:value-of select="group[@nr = 3]"/> 
     </xsl:element> 
    </xsl:template> 

</xsl:stylesheet>