问题描述
我有一个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中做到这一点?
解决方法
一些背景
不幸的是,XML不是regular language,因此,您将无法使用正则表达式可靠地对其进行处理-无论您将要使用的正则表达式多么复杂。
例如,对示例进行的简单更改可能会破坏您的处理,例如:
<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>
您不能明智地将句子的两部分之间的空格删除-因为它是作者的意图。
好吧,完整的故事在the section called "White Space Handling" of the XML spec中定义。
外行尝试用XML描述空格处理的尝试如下:
-
XML规范本身没有为空格赋予任何特殊含义:决定XML文档的特定位置中的空白是什么该文档的处理者。
通过扩展,该规范没有规定任何“标签”(
<foo>
和</bar>
和<quux/>
事物之间的空白)是否出现在是否重要:只有您来决定。
为了更好地了解其原因,请考虑以下文档:<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␣
出现在两个标签之间,并且包含前导空格和尾随空格,显然是重要;如果不是,则强调文本(标有{ {1}}将与前面的文本粘合在一起。相同的逻辑适用于换行符和
<em>…</em>
标记之后的更多文本。 -
XML规范提示,定义“无关紧要”的空白可能很方便,以表示一对未定义单个元素的相邻标记之间的任何空白。
XML还有两个特征,这些特征使处理进一步复杂化:
- 字符实体(那些
</em>
和&
东西)允许直接插入任何Unicode代码点:例如,<
将插入换行符。 - XML支持特殊的"CDATA sections",您的解析器表面上对此一无所知。
解决方案的方法
在尝试提出解决方案之前,我们先定义要忽略的空白,然后丢弃。
类似于您的文档,其定义应为:除非两个条件,否则删除任何两个标签之间的任何字符数据:
- 它至少包含一个单一的非空白字符,或者
- 它完全定义了单个XML元素的内容。
考虑到这些注意事项,我们可以编写将输入XML流解析为 tokens 并将其写入输出XML流中的代码,同时将以下逻辑应用于处理令牌:
-
如果看到除字符数据之外的任何XML元素,则将它们编码为输出流。
此外,如果该元素是开始标签,它会通过设置一些标志来记住这一事实;否则将清除该标志。
-
如果看到任何字符数据,它将检查该字符数据是否紧跟在起始元素(开始标记)之后,如果是,则将该字符数据块保存起来。
当已经存在已保存的字符数据块时,也将保存字符数据块,这是必需的,因为在XML中,文档中可能有多个相邻但仍然不同的字符数据块。
-
如果看到任何XML元素,并且检测到它具有一个或多个保存的字符块,则它首先决定是否将其放入输出流:
-
如果元素是结束元素(结束标记),则所有字符数据块都必须“按原样”放入输出流中,因为它们完全定义了单个元素的内容。
-
否则,如果至少一个已保存的字符数据块包含至少一个非空白字符,则所有块均按原样写入输出流。
-
否则将跳过所有块。
-
以下是实现上述方法的工作代码:

我不确定它能否完全涵盖所有可能的怪异案例,但这应该是一个好的开始。
,尤里卡
首先需要从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
,您可以简单地删除new line
和tab
字符,如下所示:
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)
}
结果:
<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>
,
删除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
}
RegEx说明
\ s -匹配任何空格,包括制表符,换行符,换页符,回车符和空格
+ -匹配一个或多个空格字符
RegEx语法参考: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
}