亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何從 XML 字符串中刪除 XML 意圖。?

如何從 XML 字符串中刪除 XML 意圖。?

Go
森林海 2022-06-27 10:51:44
我有一個 XML 字符串。我無法從 XML 字符串中刪除縮進空間。我更換了換行符。  <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>如何從 GOLANG 中的字符串中刪除 XML 縮進空格?我希望這個 XML 像字符串一樣,<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>如何在 GOLANG 中做到這一點?
查看完整描述

3 回答

?
Smart貓小萌

TA貢獻1911條經驗 獲得超7個贊

一些背景

不幸的是,XML 不是一種正則語言,因此您根本無法使用正則表達式可靠地處理它——無論您能想出多么復雜的正則表達式。


我會從這個問題的精彩幽默開始,然后閱讀,比如說,這個。


為了演示,對您的示例進行一個簡單的更改會破壞您的處理,例如,這可能是:


  <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>

其實考慮到這個


<last>Von

Neumann</last>

為什么您認為您可以自由地從該元素的內容中刪除換行符?


當然,你會說一個人不能明智地在他們的姓氏中使用換行符。

好的,但是這個呢?


<poem author="Chauser">

  <strophe number="1">  The lyf so short,

  the craft so long to lerne.</strophe>

</poem>

您不能明智地刪除該句子的兩個部分之間的空格 - 因為這是作者的意圖。

好吧,完整的故事在 XML 規范的“空白處理”部分中定義。
外行人嘗試在 XML 中描述空白處理如下:

  • XML 規范本身并沒有為空白指定任何特殊含義:關于空白在XML 文檔的特定位置中的含義的決定取決于該文檔的處理器。

    通過擴展,該規范不強制任何“標簽”(那些<foo></bar><quux/>事物 - 出現在允許 XML 標記的點)之間的空白是否重要:只有您自己決定。
    為了更好地理解其原因,請考慮以下文檔:

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

    這是一個完全有效的 XML,出于顯示目的,我已將標記之后和<p>標記之前的空格字符替換<em>為 Unicode“打開框”字符。

    請注意,整個文本?Some text which contains an?出現在兩個標簽之間,并且包含明顯重要的前導和尾隨空格- 如果不是,則強調的文本(用 標記的文本<em>…</em>將與前面的文本粘合在一起)。

    </em>相同的邏輯適用于標簽后的換行符和更多文本。

  • XML 規范暗示將“無關緊要”的空白定義為表示一對相鄰標簽之間的任何空白可能很方便,這些標簽不定義單個元素。

XML 還有兩個使處理更加復雜的特征:

  • 字符實體(那些&amp;&lt;事物)允許直接插入任何 Unicode 代碼點:例如,&#x000d;將插入換行符。

  • XML 支持特殊的“CDATA 部分”,您的解析器表面上對此一無所知。

解決方法

在我們嘗試提出解決方案之前,我們將定義我們打算將哪些空白視為無關緊要并丟棄。

看起來像您的文檔類型,定義應該是:任何兩個標簽之間的任何字符數據都應該被刪除,除非:

  • 它至少包含一個非空白字符,或

  • 它完全定義了單個 XML 元素的內容。

考慮到這些考慮,我們可以編寫代碼,將輸入 XML 流解析為令牌并將它們寫入輸出 XML 流,同時應用以下邏輯來處理令牌:

  1. 如果它看到除字符數據之外的任何 XML 元素,它會將它們編碼到輸出流中。

    此外,如果該元素是一個開始標簽,它會通過設置一些標志來記住這一事實;否則標志被清除。

  2. 如果它看到任何字符數據,它會檢查該字符數據是否緊跟在開始元素(開始標記)之后,如果是,則保存該字符數據塊。

    當已經存在這樣的已保存塊時,也會保存字符數據塊——這是必需的,因為在 XML 中,文檔中可能有幾個相鄰但仍然不同的字符數據塊。

  3. 如果它看到任何 XML 元素,并檢測到它有一個或多個保存的字符塊,那么它首先決定是否將它們放入輸出流:

    • 如果元素是結束元素(結束標記),則所有字符數據塊都必須“按原樣”放入輸出流中——因為它們完全定義了單個元素的內容。

    • 否則,如果至少一個已保存的字符數據塊包含至少一個非空白字符,則所有塊都按原樣寫入輸出流。

    • 否則將跳過所有塊。

這是實現所描述方法的工作代碼:

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

}

游樂場。


我不確定它是否完全涵蓋了所有可能的奇怪情況,但它應該是一個好的開始。


查看完整回答
反對 回復 2022-06-27
?
aluckdog

TA貢獻1847條經驗 獲得超7個贊

刪除 XML 標記之間的純空格序列

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 - 匹配任何空格,包括制表符、換行符、換頁符、回車符和空格


+ - 匹配一個或多個空白字符


正則表達式語法參考: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 中的可運行示例

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


查看完整回答
反對 回復 2022-06-27
?
斯蒂芬大帝

TA貢獻1827條經驗 獲得超8個贊

首先需要從 XML 中刪除縮進,然后需要刪除換行符。


// 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


查看完整回答
反對 回復 2022-06-27
  • 3 回答
  • 0 關注
  • 144 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號