0
votes

Comment supprimer les intentions XML de la chaîne XML.?

J'ai une chaîne XML. Je ne parviens pas à supprimer l'espace d'indentation de la chaîne XML. J'ai remplacé les nouvelles lignes.

<person id="13"><name><first>John</first><last>Doe</last></name><age>42</age><Married>false</Married><City>Hanga Roa</City><State>Easter Island</State><!-- Need more details. --></person>

Comment supprimer les espaces d'indentation XML d'une chaîne dans GOLANG?

Je veux ce XML sous forme de chaîne comme,

  <person id="13">
      <name>
          <first>John</first>
          <last>Doe</last>
      </name>
      <age>42</age>
      <Married>false</Married>
      <City>Hanga Roa</City>
      <State>Easter Island</State>
      <!-- Need more details. -->
  </person>

Comment faire cela en GOLANG?


2 commentaires

Montrez-nous ce que vous avez essayé jusqu'à présent afin que nous puissions vous aider.


Merci - Markus W Mahlberg. J'ai résolu ça.


4 Réponses :


0
votes

Eureka,

Vous devez d'abord supprimer l'indentation de XML, puis supprimer la nouvelle ligne.

// Regex to remove indentation
m1 := regexp.MustCompile(`( *)<`)
newstr := m1.ReplaceAllString(xmlString, "<")

// Replace newline
newLineReplacer := strings.NewReplacer("\n", "", "\r\n", "")
xmlString = newLineReplacer.Replace(newstr)

Trouvez ceci ici, https://play.golang.org/p/Orp2RyPbGP2


0 commentaires

2
votes

Un peu de contexte

Malheureusement, XML n'est pas un langage régulier , et par conséquent vous ne pouvez tout simplement pas le traiter de manière fiable en utilisant une expression régulière - quelle que soit la complexité d'une expression rationnelle que vous serez en mesure de créer.

Je commencerais par cette brillante interprétation humoristique de ce problème, puis je lisais, disons, ceci .

Pour démontrer, un simple changement à votre exemple qui interrompra votre traitement pourrait être, par exemple, ceci:

package main

import (
    "encoding/xml"
    "errors"
    "fmt"
    "io"
    "os"
    "strings"
)

const xmlData = `<?xml version="1.0" encoding="utf-8"?>
  <person id="13">
      weird text
      <name>
          <first>John</first>
          <last><![CDATA[Johnson & ]]><![CDATA[ <<Johnson>> ]]><![CDATA[ & Doe ]]></last>
      </name>&#x000d;&#x0020;&#x000a;&#x0009;<age>
      42
      </age>
      <Married>false</Married>
      <City><![CDATA[Hanga <Roa>]]></City>
      <State>Easter Island</State>
      <!-- Need more details. --> what?
      <foo> more <bar/> text </foo>
  </person>
`

func main() {
    stripped, err := removeWS(xmlData)
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
    fmt.Print(stripped)
}

func removeWS(s string) (string, error) {
    dec := xml.NewDecoder(strings.NewReader(s))

    var sb strings.Builder
    enc := NewSkipWSEncoder(&sb)

    for {
        tok, err := dec.Token()
        if err != nil {
            if err == io.EOF {
                break
            }
            return "", fmt.Errorf("failed to decode token: %w", err)
        }

        err = enc.EncodeToken(tok)
        if err != nil {
            return "", fmt.Errorf("failed to encode token: %w", err)
        }
    }

    err := enc.Flush()
    if err != nil {
        return "", fmt.Errorf("failed to flush encoder: %w", err)
    }

    return sb.String(), nil
}

type SkipWSEncoder struct {
    *xml.Encoder

    sawStartElement bool
    charData        []xml.CharData
}

func NewSkipWSEncoder(w io.Writer) *SkipWSEncoder {
    return &SkipWSEncoder{
        Encoder: xml.NewEncoder(w),
    }
}

func (swe *SkipWSEncoder) EncodeToken(tok xml.Token) error {
    if cd, isCData := tok.(xml.CharData); isCData {
        if len(swe.charData) > 0 || swe.sawStartElement {
            swe.charData = append(swe.charData, cd.Copy())
            return nil
        }
        if isWS(cd) {
            return nil
        }
        return swe.Encoder.EncodeToken(tok)
    }

    if len(swe.charData) > 0 {
        _, isEndElement := tok.(xml.EndElement)
        err := swe.flushSavedCharData(isEndElement)
        if err != nil {
            return err
        }
    }

    _, swe.sawStartElement = tok.(xml.StartElement)

    return swe.Encoder.EncodeToken(tok)
}

func (swe *SkipWSEncoder) Flush() error {
    if len(swe.charData) > 0 {
        return errors.New("attempt to flush encoder while having pending cdata")
    }
    return swe.Encoder.Flush()
}

func (swe *SkipWSEncoder) flushSavedCharData(mustKeep bool) error {
    if mustKeep || !allIsWS(swe.charData) {
        err := encodeCDataList(swe.Encoder, swe.charData)
        if err != nil {
            return err
        }
    }

    swe.charData = swe.charData[:0]

    return nil
}

func encodeCDataList(enc *xml.Encoder, cdataList []xml.CharData) error {
    for _, cd := range cdataList {
        err := enc.EncodeToken(cd)
        if err != nil {
            return err
        }
    }
    return nil
}

func isWS(b []byte) bool {
    for _, c := range b {
        switch c {
        case 0x20, 0x09, 0x0d, 0x0a:
            continue
        }
        return false
    }
    return true
}

func allIsWS(cdataList []xml.CharData) bool {
    for _, cd := range cdataList {
        if !isWS(cd) {
            return false
        }
    }
    return true
}

En fait, considérez ceci

<p>␣Some text which contains an␣<em>emphasized block</em>
which is followed by a linebreak and more text.</p>

Pourquoi pensez-vous que vous êtes libre de supprimer le saut de ligne du contenu de cet élément?

Bien sûr, vous direz que personne ne peut raisonnablement avoir une nouvelle ligne dans son nom de famille.
OK, mais qu'en est-il de ça?

<poem author="Chauser">
  <strophe number="1">  The lyf so short,
  the craft so long to lerne.</strophe>
</poem>

Vous ne pouvez pas supprimer raisonnablement l'espace entre les deux parties de cette phrase - parce que l'avoir était l'intention de l'auteur.

Eh bien, OK, l'histoire complète est définie dans la section intitulée "Gestion des espaces blancs" de la spécification XML .
La tentative d'un profane pour décrire la gestion des espaces blancs dans XML est la suivante:

  • La spécification XML lui - même ne lui confère pas de sens particulier aux espaces: la décision sur ce moyen des espaces dans un lieu paricular d'un document XML est en place au processeur de ce document.

    Par extension, la spécification n'impose pas si les espaces entre les "balises" (ces <foo> et </bar> et <quux/> choses - apparaissant aux points où le balisage XML est autorisé) sont significatifs ou non: c'est seulement vous qui décide.
    Pour mieux comprendre la raison de cela, considérez le document suivant:

    <last>Von
    Neumann</last>
    

    C'est un XML parfaitement valide, et j'ai remplacé les caractères d'espacement juste après la <p> et juste avant la <em> par les caractères Unicode "boîte ouverte" à des fins d'affichage.

    Notez que tout le texte - â £Some text which contains anâ £ apparaît entre deux balises et contient des espaces blancs de â £Some text which contains anâ £ et de fin, ce qui est évidemment significatif - si ce n'est pas le cas, le texte mis en évidence (qui est marqué par <em>…</em> serait collé avec le texte précédent).

    La même logique s'applique au saut de ligne et plus de texte après la </em> .

  • La spécification XML laisse entendre qu'il peut être pratique de définir un espace blanc "insignifiant" pour désigner tout espace blanc entre une paire de balises adjacentes qui ne définissent pas un seul élément.

XML a également deux fonctionnalités qui compliquent davantage le traitement:

  • Les entités de caractères (ces &amp; et &lt; trucs) permettent l'insertion directe de tout point de code Unicode: par exemple, &#x000d; insérerait un caractère de saut de ligne.
  • XML supporte des "sections CDATA" spéciales, dont votre parseur ne sait apparemment rien.

Une approche de la solution

Avant d'essayer de trouver une solution, nous allons définir les espaces que nous avons l'intention de traiter comme insignifiants et supprimer.

Il semble que pour votre type de document, la définition devrait être: toute donnée de caractère entre deux balises doit être supprimée à moins que:

  • il contient au moins un caractère unique sans espace, ou
  • il définit complètement le contenu d'un seul élément XML.

En gardant ces considérations à l'esprit, nous pouvons écrire du code qui analyse un flux XML d'entrée en jetons et les écrit dans le flux XML de sortie, tout en appliquant la logique suivante au traitement des jetons:

  1. S'il voit un élément XML autre que des données de caractères, il les encode dans le flux de sortie.

    De plus, si cet élément était une balise de début, il se souvient de ce fait en définissant un indicateur; sinon, le drapeau est effacé.

  2. S'il voit des données de caractère, il vérifie si ces données de caractère suivent immédiatement un élément de début (une balise d'ouverture), et si tel est le cas, ce bloc de données de caractère est sauvegardé.

    Le bloc de données de caractères est également enregistré lorsqu'il existe déjà de tels blocs enregistrés - cela est nécessaire car en XML, il est possible d'avoir plusieurs blocs de données de caractères adjacents mais toujours distincts dans un document.

  3. S'il voit un élément XML et détecte qu'il contient un ou plusieurs blocs de caractères enregistrés, il a d'abord décidé s'il fallait les placer dans le flux de sortie:

    • Si l'élément est un élément de fin (la balise de fermeture), tous les blocs de données de caractères doivent être placés dans le flux de sortie "tels quels" - car ils définissent complètement le contenu d'un seul élément.

    • Sinon, si au moins un des blocs de données de caractères enregistrés contient au moins un seul caractère non blanc, tous les blocs sont écrits dans le flux de sortie tels quels.

    • Sinon, tous les blocs sont ignorés.

Voici le code de travail qui implémente l'approche décrite:

  <person id="13">
      <name>
          <first>John</first>
          <last>Doe</last>
      </name>
      <age>42</age>
      <Married>false</Married>
      <City><![CDATA[Hanga <<Roa>>]]></City>
      <State>Easter Island</State>
      <!-- Need more details. -->
  </person>

Aire de jeux .

Je ne suis pas sûr que cela couvre complètement tous les cas étranges possibles, mais cela devrait être un bon début.


0 commentaires

0
votes

Vous pouvez simplement supprimer la new line et le caractère de tab comme suit:

<person id="13"><name><first>John</first><last>Doe</last></name><age>42</age><Married>false</Married><City>Hanga Roa</City><State>Easter Island</State><!-- Need more details. --></person>

Résultat:

package main

import (
    "fmt"
    "strings"
)

func main() {
    var s = `<person id="13">
    <name>
        <first>John</first>
        <last>Doe</last>
    </name>
    <age>42</age>
    <Married>false</Married>
    <City>Hanga Roa</City>
    <State>Easter Island</State>
    <!-- Need more details. -->
</person>`
    for {
        if strings.Contains(s, "\n") {
            s = strings.ReplaceAll(s, "\n", "")
        }
        if strings.Contains(s, "\t") {
            s = strings.ReplaceAll(s, "\t", "")
        }
        if !strings.Contains(s, "\n") && !strings.Contains(s, "\t") {
            break
        }
    }
    fmt.Println(s)
}


0 commentaires

0
votes

Supprimer les séquences d'espaces uniquement entre les balises XML
package main

import (
    "fmt"
    "regexp"
    "strings"
)

func main() {
    var s = `    
<person id="13">
    <name>
        <first>John</first>
        <last>Doe</last>
    </name>
    <age>42</age>
    <Married>false</Married>
    <City>Hanga Roa</City>
    <State>Easter Island</State>
    <!-- Need more details. -->
</person>   `

    s = unformatXML(s)
    fmt.Println(fmt.Sprintf("'%s'", s)) // single quotes used to confirm no leading or trailing whitespace
}

func unformatXML(xmlString string) string {
    var unformatXMLRegEx = regexp.MustCompile(`>\s+<`)
    unformatBetweenTags := unformatXMLRegEx.ReplaceAllString(xmlString, "><") // remove whitespace between XML tags
    return strings.TrimSpace(unformatBetweenTags) // remove whitespace before and after XML
}

Explication RegEx

\ s - correspond à tous les espaces, y compris tabulation, nouvelle ligne, saut de page, retour chariot et espace

+ - correspond à un ou plusieurs caractères d'espacement

Référence de syntaxe RegEx: https://golang.org/pkg/regexp/syntax/

Exemple

func unformatXML(xmlString string) string {
    var unformatXMLRegEx = regexp.MustCompile(`>\s+<`)
    unformatBetweenTags := unformatXMLRegEx.ReplaceAllString(xmlString, "><") // remove whitespace between XML tags
    return strings.TrimSpace(unformatBetweenTags) // remove whitespace before and after XML
}

Exemple exécutable dans Go Playground

https://play.golang.org/p/VS1LRNevicz


0 commentaires