在使用xml.dom.minidom时如何转义'<'和'>'在xml中
我在用xml.dom.minidom处理xml文件时,遇到了在文件中转义"<"和">"的问题。
我试着获取它们的unicode十六进制值,然后用那个来代替。
http://slayeroffice.com/tools/unicode_lookup/
我也尝试过使用标准的"<"和">",但还是没有成功。
from xml.dom.minidom import Document
doc = Document()
e = doc.createElement("abc")
s1 = '<hello>bhaskar</hello>'
text = doc.createTextNode(s1)
e.appendChild(text)
e.toxml()
'<abc><hello>bhaskar</hello></abc>'
用writexml()得到的结果也是一样。我还尝试在toxml()和writexml()调用中指定编码为'UTF-8'、'utf-8'、'utf',但结果还是一样。
from xml.dom.minidom import Document
doc = Document()
e = doc.createElement("abc")
s1 = u'<hello>bhaskar</hello>'
text = doc.createTextNode(s1)
e.appendChild(text)
e.toxml()
u'<abc>&lt;hello&gt;bhaskar&lt;/hello&gt;</abc>'
我尝试了其他方法,但结果还是一样。唯一能解决这个问题的方法就是重写写入器。
import xml.dom.minidom as md
# XXX Hack to handle '<' and '>'
def wd(writer, data):
data = data.replace("<", "<").replace(">", ">")
writer.write(data)
md._write_data = wd
编辑 - 这是代码。
import xml.dom.minidom as md
doc = md.Document()
entity_descr = doc.createElement("EntityDescriptor")
doc.appendChild(entity_descr)
entity_descr.setAttribute('xmlns', 'urn:oasis:names:tc:SAML:2.0:metadata')
entity_descr.setAttribute('xmlns:saml', 'urn:oasis:names:tc:SAML:2.0:assertion')
entity_descr.setAttribute('xmlns:ds', 'http://www.w3.org/2000/09/xmldsig#')
# Get the entity_id from saml20_idp_settings
entity_descr.setAttribute('entityID', self.group['entity_id'])
idpssodescr = doc.createElement('IDPSSODescriptor')
idpssodescr.setAttribute('WantAuthnRequestsSigned', 'true')
idpssodescr.setAttribute('protocolSupportEnumeration',
'urn:oasis:names:tc:SAML:2.0:protocol')
entity_descr.appendChild(idpssodescr)
keydescr = doc.createElement('KeyDescriptor')
keydescr.setAttribute('use', 'signing')
idpssodescr.appendChild(keydescr)
keyinfo = doc.createElement('ds:KeyInfo')
keyinfo.setAttribute('xmlns:ds', 'http://www.w3.org/2000/09/xmldsig#')
keydescr.appendChild(keyinfo)
x509data = doc.createElement('ds:X509Data')
keyinfo.appendChild(x509data)
# check this part
s = "this is a cert blah blah"
x509cert = doc.createElement('ds:X509Certificate')
cert = doc.createTextNode(s)
x509cert.appendChild(cert)
x509data.appendChild(x509cert)
sso = doc.createElement('SingleSignOnService')
sso.setAttribute('Binding', 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect')
sso.setAttribute('Location', 'http://googleapps/singleSignOn')
idpssodescr.appendChild(sso)
# Write the metadata file.
fobj = open('metadata.xml', 'w')
doc.writexml(fobj, " ", "", "\n", "UTF-8")
fobj.close()
这段代码产生了
<?xml version="1.0" encoding="UTF-8"?>
<EntityDescriptor entityID="skar" xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
<IDPSSODescriptor WantAuthnRequestsSigned="true"
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>
this is a cert blah blah
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</KeyDescriptor>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="http:///singleSignOn"/>
</IDPSSODescriptor>
</EntityDescriptor>
注意到"这是一个证书"是单独出来的。我为这个问题绞尽脑汁,但结果还是一样。
2 个回答
如果你在XML中使用 "<"
这个符号作为文本,那你需要对它进行转义,不然它会被当作标记来处理。所以,xml.dom在这里进行转义是正确的,因为你是想要一个文本节点。
假设你真的想插入一段XML,我建议你使用 createElement("hello")
。如果你有一段不知道结构的XML片段,最好先解析它,然后再把解析出来的节点放到其他树结构中。
如果你想要深入研究,可以从xml.dom.minidom.Text这个类继承,并重写writexml方法。具体的细节可以查看minidom的源代码。
这不是一个错误,而是一个功能。如果你想插入真正的XML,应该插入DOM对象。不过,XML标签里的文本需要进行实体转义,这样才能算是有效的XML。
from xml.dom.minidom import Document
doc = Document()
e = doc.createElement("abc")
eh = doc.createElement("hello")
s1 = 'bhaskar'
text = doc.createTextNode(s1)
eh.appendChild(text)
e.appendChild(eh)
e.toxml()
编辑:我不知道Python的API是什么样的,但看起来和C#的很相似,所以你可能可以用类似 e.innerXml = s1
的方式来实现你想做的事情……不过这样可能会有问题。更好的做法是解析它,然后用 appendChild
来添加。
编辑 2:我刚在本地用Python运行了一下,发现问题出在你这边,而不是库的原因。一定要确保你的字符串开头没有换行符或空格。作为参考,我用的测试代码是:
Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41)
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from xml.dom.minidom import Document
>>> cert = "---- START CERTIFICATE ----\n Hello world\n---- END CERTIFICATE ---"
>>> doc = Document()
>>> e = doc.createElement("cert")
>>> certEl = doc.createTextNode(cert)
>>> e.appendChild(certEl)
<DOM Text node "'---- START'...">
>>> print e.toxml()
<cert>---- START CERTIFICATE ----
Hello world
---- END CERTIFICATE ---</cert>
>>>
编辑 3:最后一次编辑。问题出在你调用的 writexml
。只需使用以下代码就能解决这个问题:
doc.writexml(fobj)
# or
doc.writexml(fobj, "", " ", "")
不幸的是,似乎你无法使用 newline
参数来实现漂亮的打印……看起来Python库(至少是 minidom
)写得相当糟糕,在打印时会修改TextNode。这并不是说实现得差,而是有些天真。真是可惜……