3 回答

TA貢獻(xiàn)1911條經(jīng)驗(yàn) 獲得超7個贊
一些背景
不幸的是,XML 不是一種正則語言,因此您根本無法使用正則表達(dá)式可靠地處理它——無論您能想出多么復(fù)雜的正則表達(dá)式。
我會從這個問題的精彩幽默開始,然后閱讀,比如說,這個。
為了演示,對您的示例進(jìn)行一個簡單的更改會破壞您的處理,例如,這可能是:
<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>
其實(shí)考慮到這個
<last>Von
Neumann</last>
為什么您認(rèn)為您可以自由地從該元素的內(nèi)容中刪除換行符?
當(dāng)然,你會說一個人不能明智地在他們的姓氏中使用換行符。
好的,但是這個呢?
<poem author="Chauser">
<strophe number="1"> The lyf so short,
the craft so long to lerne.</strophe>
</poem>
您不能明智地刪除該句子的兩個部分之間的空格 - 因?yàn)檫@是作者的意圖。
好吧,完整的故事在 XML 規(guī)范的“空白處理”部分中定義。
外行人嘗試在 XML 中描述空白處理如下:
XML 規(guī)范本身并沒有為空白指定任何特殊含義:關(guān)于空白在XML 文檔的特定位置中的含義的決定取決于該文檔的處理器。
通過擴(kuò)展,該規(guī)范不強(qiáng)制任何“標(biāo)簽”(那些
<foo>
和</bar>
和<quux/>
事物 - 出現(xiàn)在允許 XML 標(biāo)記的點(diǎn))之間的空白是否重要:只有您自己決定。
為了更好地理解其原因,請考慮以下文檔:<p>?Some text which contains an?<em>emphasized block</em>which is followed by a linebreak and more text.</p>
這是一個完全有效的 XML,出于顯示目的,我已將標(biāo)記之后和
<p>
標(biāo)記之前的空格字符替換<em>
為 Unicode“打開框”字符。請注意,整個文本
?Some text which contains an?
出現(xiàn)在兩個標(biāo)簽之間,并且包含明顯重要的前導(dǎo)和尾隨空格- 如果不是,則強(qiáng)調(diào)的文本(用 標(biāo)記的文本<em>…</em>
將與前面的文本粘合在一起)。</em>
相同的邏輯適用于標(biāo)簽后的換行符和更多文本。XML 規(guī)范暗示將“無關(guān)緊要”的空白定義為表示一對相鄰標(biāo)簽之間的任何空白可能很方便,這些標(biāo)簽不定義單個元素。
XML 還有兩個使處理更加復(fù)雜的特征:
字符實(shí)體(那些
&
和<
事物)允許直接插入任何 Unicode 代碼點(diǎn):例如,
將插入換行符。XML 支持特殊的“CDATA 部分”,您的解析器表面上對此一無所知。
解決方法
在我們嘗試提出解決方案之前,我們將定義我們打算將哪些空白視為無關(guān)緊要并丟棄。
看起來像您的文檔類型,定義應(yīng)該是:任何兩個標(biāo)簽之間的任何字符數(shù)據(jù)都應(yīng)該被刪除,除非:
它至少包含一個非空白字符,或
它完全定義了單個 XML 元素的內(nèi)容。
考慮到這些考慮,我們可以編寫代碼,將輸入 XML 流解析為令牌并將它們寫入輸出 XML 流,同時(shí)應(yīng)用以下邏輯來處理令牌:
如果它看到除字符數(shù)據(jù)之外的任何 XML 元素,它會將它們編碼到輸出流中。
此外,如果該元素是一個開始標(biāo)簽,它會通過設(shè)置一些標(biāo)志來記住這一事實(shí);否則標(biāo)志被清除。
如果它看到任何字符數(shù)據(jù),它會檢查該字符數(shù)據(jù)是否緊跟在開始元素(開始標(biāo)記)之后,如果是,則保存該字符數(shù)據(jù)塊。
當(dāng)已經(jīng)存在這樣的已保存塊時(shí),也會保存字符數(shù)據(jù)塊——這是必需的,因?yàn)樵?XML 中,文檔中可能有幾個相鄰但仍然不同的字符數(shù)據(jù)塊。
如果它看到任何 XML 元素,并檢測到它有一個或多個保存的字符塊,那么它首先決定是否將它們放入輸出流:
如果元素是結(jié)束元素(結(jié)束標(biāo)記),則所有字符數(shù)據(jù)塊都必須“按原樣”放入輸出流中——因?yàn)樗鼈兺耆x了單個元素的內(nèi)容。
否則,如果至少一個已保存的字符數(shù)據(jù)塊包含至少一個非空白字符,則所有塊都按原樣寫入輸出流。
否則將跳過所有塊。
這是實(shí)現(xiàn)所描述方法的工作代碼:
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
}
游樂場。
我不確定它是否完全涵蓋了所有可能的奇怪情況,但它應(yīng)該是一個好的開始。

TA貢獻(xiàn)1847條經(jīng)驗(yàn) 獲得超7個贊
刪除 XML 標(biāo)記之間的純空格序列
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
}
正則表達(dá)式解釋
\s - 匹配任何空格,包括制表符、換行符、換頁符、回車符和空格
+ - 匹配一個或多個空白字符
正則表達(dá)式語法參考:https ://golang.org/pkg/regexp/syntax/
例子
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
}
Go Playground 中的可運(yùn)行示例
https://play.golang.org/p/VS1LRNevicz

TA貢獻(xiàn)1827條經(jīng)驗(yàn) 獲得超8個贊
首先需要從 XML 中刪除縮進(jìn),然后需要刪除換行符。
// Regex to remove indentation
m1 := regexp.MustCompile(`( *)<`)
newstr := m1.ReplaceAllString(xmlString, "<")
// Replace newline
newLineReplacer := strings.NewReplacer("\n", "", "\r\n", "")
xmlString = newLineReplacer.Replace(newstr)
在這里找到這個,https://play.golang.org/p/Orp2RyPbGP2
- 3 回答
- 0 關(guān)注
- 142 瀏覽
添加回答
舉報(bào)