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?
4 Réponses :
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
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>
 
	<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:
&
et <
trucs) permettent l'insertion directe de tout point de code Unicode: par exemple, 
insérerait un caractère de saut de ligne.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:
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:
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é.
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.
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>
Je ne suis pas sûr que cela couvre complètement tous les cas étranges possibles, mais cela devrait être un bon début.
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) }
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 }
\ 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/
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 }
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.