使用Python写入XML文件
我需要用Python的标准库来写一个XML文件(不使用elementtree、lxml等库)。这个文件的内容是SAML身份提供者的元数据,格式如下 -
<?xml version="1.0"?>
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
entityID="http://wsa.saas.com">
<IDPSSODescriptor>
<KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data><ds:X509Certificate>-----BEGIN CERTIFICATE-----
MIIDnjCCAoagAwIBAgIBATANBgkqhkiG9w0BAQUFADBUMQswCQYDVQQGEwJGUjEP
MA0GA1UECBMGRnJhbmNlMQ4wDAYDVQQHEwVQYXJpczETMBEGA1UEChMKRW50cm91
dmVydDEPMA0GA1UEAxMGRGFtaWVuMB4XDTA2MTAyNzA5MDc1NFoXDTExMTAyNjA5
MDc1NFowVDELMAkGA1UEBhMCRlIxDzANBgNVBAgTBkZyYW5jZTEOMAwGA1UEBxMF
UGFyaXMxEzARBgNVBAoTCkVudHJvdXZlcnQxDzANBgNVBAMTBkRhbWllbjCCASIw
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM06Hx6VgHYR9wUf/tZVVTRkVWNq
h9x+PvHA2qH4OYMuqGs4Af6lU2YsZvnrmRdcFWv0+UkdAgXhReCWAZgtB1pd/W9m
6qDRldCCyysow6xPPKRz/pOTwRXm/fM0QGPeXzwzj34BXOIOuFu+n764vKn18d+u
uVAEzk1576pxTp4pQPzJfdNLrLeQ8vyCshoFU+MYJtp1UA+h2JoO0Y8oGvywbUxH
ioHN5PvnzObfAM4XaDQohmfxM9Uc7Wp4xKAc1nUq5hwBrHpjFMRSz6UCfMoJSGIi
+3xJMkNCjL0XEw5NKVc5jRKkzSkN5j8KTM/k1jPPsDHPRYzbWWhnNtd6JlkCAwEA
AaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0
ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFP2WWMDShux3iF74+SoO1xf6qhqaMB8G
A1UdIwQYMBaAFGjl6TRXbQDHzSlZu+e8VeBaZMB5MA0GCSqGSIb3DQEBBQUAA4IB
AQAZ/imK7UMognXbs5RfSB8cMW6iNAI+JZqe9XWjvtmLfIIPbHM96o953SiFvrvQ
BZjGmmPMK3UH29cjzDx1R/RQaYTyMrHyTePLh3BMd5mpJ/9eeJCSxPzE2ECqWRUa
pkjukecFXqmRItwgTxSIUE9QkpzvuQRb268PwmgroE0mwtiREADnvTFkLkdiEMew
fiYxZfJJLPBqwlkw/7f1SyzXoPXnz5QbNwDmrHelga6rKSprYKb3pueqaIe8j/AP
NC1/bzp8cGOcJ88BD5+Ny6qgPVCrMLE5twQumJ12V3SvjGNtzFBvg2c/9S5OmVqR
LlTxKnCrWAXftSm1rNtewTsF
-----END CERTIFICATE-----
</ds:X509Certificate></ds:X509Data>
</ds:KeyInfo>
</KeyDescriptor>
<SingleSignOnService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="http://idp5/singleSignOn" />
</IDPSSODescriptor>
</EntityDescriptor>
我现在的代码是这样的 -
>>> from xml.dom.minidom import Document
>>> doc = Document()
>>> entity_descriptor = doc.createElement("EntityDescriptor")
>>> doc.appendChild(entity_descriptor)
>>> entity_descriptor.setAttribute('xmlns', 'urn:oasis:names:tc:SAML:2.0:metadata')
>>> entity_descriptor.setAttribute('xmlns:saml', 'urn:oasis:names:tc:SAML:2.0:assertion')
>>> entity_descriptor.setAttribute('xmlns:ds', 'hxxp://xxx.w3.org/2000/09/xmldsig#')
>>> entity_descriptor.setAttribute('entityID', 'hxxp://wsa.saas.com')
>>> idpssodescr = doc.createElement('IDPSSODescriptor')
>>> entity_descriptor.appendChild(idpssodescr)
>>> keydescr = doc.createElement('KeyDescriptor')
>>> keydescr.setAttribute('use', 'signing')
>>> idpssodescr.appendChild(keydescr)
>>> keyinfo = doc.createElement('ds:KeyInfo')
>>> keyinfo.setAttribute('xmlns:ds', 'http://xxx.w3.org/2000/09/xmldsig#')
>>> keydescr.appendChild(keyinfo)
>>> x509data = doc.createElement('ds:X509Data')
>>> keyinfo.appendChild(x509data)
>>> x509cert = doc.createElement('ds:X509Certificate')
>>> ptext = doc.createTextNode("This is a test!")
>>> x509cert.appendChild(ptext)
>>> x509data.appendChild(x509cert)
>>> sso = doc.createElement('SingleSignOnService')
>>> sso.setAttribute('Binding', 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect')
>>> sso.setAttribute('Location', 'hxxx://idp5/singleSignOn')
>>> idpssodescr.appendChild(sso)
>>> print doc.toprettyxml(indent=" ")
<?xml version="1.0" ?>
<EntityDescriptor entityID="http://wsa.saas.com" 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>
<KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>
This is a test!
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</KeyDescriptor>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://idp5/singleSignOn"/>
</IDPSSODescriptor>
</EntityDescriptor>
我对证书的部分有点困惑。原始的格式是 <ds:X509Certificate>-----BEGIN CERTIFICATE---.....</ds:X509Certificate>
,而我写的格式是:
<ds:X509Certificate>
This is the cert
</ds:X509Certificate>
抱歉,我对XML的经验不多。我的代码适合这个任务吗?
谢谢。
3 个回答
0
Yattag 可能在这方面会很有趣。
from yattag import Doc, indent
doc, tag, text = Doc().tagtext()
doc.asis('<?xml version="1.0"?>')
with tag('EntityDescriptor',
("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion"),
("xmlns:ds", "http://www.w3.org/2000/09/xmldsig#"),
entityID = "http://wsa.saas.com",
xmlns = "urn:oasis:names:tc:SAML:2.0:metadata"):
with tag('IDPSSODescriptor'):
with tag('KeyDescriptor', use='signing'):
with tag('ds:KeyInfo',
("xmlns:ds", "http://www.w3.org/2000/09/xmldsig#")):
with tag('ds:X509Data'):
with tag('ds:X509Certificate'):
text(
"""-----BEGIN CERTIFICATE-----
MIIDnjCCAoagAwIBAgIBATANBgkqhkiG9w0BAQUFADBUMQswCQYDVQQGEwJGUjEP
MA0GA1UECBMGRnJhbmNlMQ4wDAYDVQQHEwVQYXJpczETMBEGA1UEChMKRW50cm91
dmVydDEPMA0GA1UEAxMGRGFtaWVuMB4XDTA2MTAyNzA5MDc1NFoXDTExMTAyNjA5
MDc1NFowVDELMAkGA1UEBhMCRlIxDzANBgNVBAgTBkZyYW5jZTEOMAwGA1UEBxMF
UGFyaXMxEzARBgNVBAoTCkVudHJvdXZlcnQxDzANBgNVBAMTBkRhbWllbjCCASIw
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM06Hx6VgHYR9wUf/tZVVTRkVWNq
h9x+PvHA2qH4OYMuqGs4Af6lU2YsZvnrmRdcFWv0+UkdAgXhReCWAZgtB1pd/W9m
6qDRldCCyysow6xPPKRz/pOTwRXm/fM0QGPeXzwzj34BXOIOuFu+n764vKn18d+u
uVAEzk1576pxTp4pQPzJfdNLrLeQ8vyCshoFU+MYJtp1UA+h2JoO0Y8oGvywbUxH
ioHN5PvnzObfAM4XaDQohmfxM9Uc7Wp4xKAc1nUq5hwBrHpjFMRSz6UCfMoJSGIi
+3xJMkNCjL0XEw5NKVc5jRKkzSkN5j8KTM/k1jPPsDHPRYzbWWhnNtd6JlkCAwEA
AaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0
ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFP2WWMDShux3iF74+SoO1xf6qhqaMB8G
A1UdIwQYMBaAFGjl6TRXbQDHzSlZu+e8VeBaZMB5MA0GCSqGSIb3DQEBBQUAA4IB
AQAZ/imK7UMognXbs5RfSB8cMW6iNAI+JZqe9XWjvtmLfIIPbHM96o953SiFvrvQ
BZjGmmPMK3UH29cjzDx1R/RQaYTyMrHyTePLh3BMd5mpJ/9eeJCSxPzE2ECqWRUa
pkjukecFXqmRItwgTxSIUE9QkpzvuQRb268PwmgroE0mwtiREADnvTFkLkdiEMew
fiYxZfJJLPBqwlkw/7f1SyzXoPXnz5QbNwDmrHelga6rKSprYKb3pueqaIe8j/AP
NC1/bzp8cGOcJ88BD5+Ny6qgPVCrMLE5twQumJ12V3SvjGNtzFBvg2c/9S5OmVqR
LlTxKnCrWAXftSm1rNtewTsF
-----END CERTIFICATE-----
""")
with tag('SingleSignOnService',
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect",
Location="http://idp5/singleSignOn"
):
pass
result = indent(
doc.getvalue(),
indentation = ' '*4,
newline = '\r\n'
)
print(result)
你可以得到:
<?xml version="1.0"?>
<EntityDescriptor xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" entityID="http://wsa.saas.com" xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<IDPSSODescriptor>
<KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>-----BEGIN CERTIFICATE-----
MIIDnjCCAoagAwIBAgIBATANBgkqhkiG9w0BAQUFADBUMQswCQYDVQQGEwJGUjEP
MA0GA1UECBMGRnJhbmNlMQ4wDAYDVQQHEwVQYXJpczETMBEGA1UEChMKRW50cm91
dmVydDEPMA0GA1UEAxMGRGFtaWVuMB4XDTA2MTAyNzA5MDc1NFoXDTExMTAyNjA5
MDc1NFowVDELMAkGA1UEBhMCRlIxDzANBgNVBAgTBkZyYW5jZTEOMAwGA1UEBxMF
UGFyaXMxEzARBgNVBAoTCkVudHJvdXZlcnQxDzANBgNVBAMTBkRhbWllbjCCASIw
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM06Hx6VgHYR9wUf/tZVVTRkVWNq
h9x+PvHA2qH4OYMuqGs4Af6lU2YsZvnrmRdcFWv0+UkdAgXhReCWAZgtB1pd/W9m
6qDRldCCyysow6xPPKRz/pOTwRXm/fM0QGPeXzwzj34BXOIOuFu+n764vKn18d+u
uVAEzk1576pxTp4pQPzJfdNLrLeQ8vyCshoFU+MYJtp1UA+h2JoO0Y8oGvywbUxH
ioHN5PvnzObfAM4XaDQohmfxM9Uc7Wp4xKAc1nUq5hwBrHpjFMRSz6UCfMoJSGIi
+3xJMkNCjL0XEw5NKVc5jRKkzSkN5j8KTM/k1jPPsDHPRYzbWWhnNtd6JlkCAwEA
AaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0
ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFP2WWMDShux3iF74+SoO1xf6qhqaMB8G
A1UdIwQYMBaAFGjl6TRXbQDHzSlZu+e8VeBaZMB5MA0GCSqGSIb3DQEBBQUAA4IB
AQAZ/imK7UMognXbs5RfSB8cMW6iNAI+JZqe9XWjvtmLfIIPbHM96o953SiFvrvQ
BZjGmmPMK3UH29cjzDx1R/RQaYTyMrHyTePLh3BMd5mpJ/9eeJCSxPzE2ECqWRUa
pkjukecFXqmRItwgTxSIUE9QkpzvuQRb268PwmgroE0mwtiREADnvTFkLkdiEMew
fiYxZfJJLPBqwlkw/7f1SyzXoPXnz5QbNwDmrHelga6rKSprYKb3pueqaIe8j/AP
NC1/bzp8cGOcJ88BD5+Ny6qgPVCrMLE5twQumJ12V3SvjGNtzFBvg2c/9S5OmVqR
LlTxKnCrWAXftSm1rNtewTsF
-----END CERTIFICATE-----
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</KeyDescriptor>
</IDPSSODescriptor>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://idp5/singleSignOn"></SingleSignOnService>
</EntityDescriptor>
0
为了记录一下,我之前的代码缺少了一个小改动,这就是为什么证书会被拒绝的原因。
from xml.dom.minidom import Document
doc = Document()
entity_descriptor = doc.createElement("EntityDescriptor")
doc.appendChild(entity_descriptor)
entity_descriptor.setAttribute('xmlns', 'urn:oasis:names:tc:SAML:2.0:metadata')
entity_descriptor.setAttribute('xmlns:saml', 'urn:oasis:names:tc:SAML:2.0:assertion')
entity_descriptor.setAttribute('xmlns:ds', 'http://www.w3.org/2000/09/xmldsig#')
entity_descriptor.setAttribute('entityID', 'http://wsa.saas.com')
idpssodescr = doc.createElement('IDPSSODescriptor')
idpssodescr.setAttribute('WantAuthnRequestsSigned', 'true')
idpssodescr.setAttribute('protocolSupportEnumeration',
'urn:oasis:names:tc:SAML:2.0:protocol')
entity_descriptor.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)
x509cert = doc.createElement('ds:X509Certificate')
# Read the certificate from some file.
fp = file('idp.crt.pem', 'r')
s = ''
for i in fp.readlines():
s+=''.join(i)
ptext = doc.createTextNode(s)
x509cert.appendChild(ptext)
x509data.appendChild(x509cert)
sso = doc.createElement('SingleSignOnService')
sso.setAttribute('Binding', 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect')
sso.setAttribute('Location', 'http://idp5/singleSignOn')
idpssodescr.appendChild(sso)
print doc.toprettyxml(indent=" ")
<?xml version="1.0" ?>
<EntityDescriptor entityID="http://wsa.saas.com"
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>
-----BEGIN CERTIFICATE-----
MIICfTCCAeagAwIBAgIJAPEn4h3J3p2dMA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV
BAYTAmFhMQswCQYDVQQKEwJhYTELMAkGA1UECxMCYWExCzAJBgNVBAMTAmFhMB4X
DTA5MTAxOTA4NTI1M1oXDTEwMTAxOTA4NTI1M1owNDELMAkGA1UEBhMCYWExCzAJ
BgNVBAoTAmFhMQswCQYDVQQLEwJhYTELMAkGA1UEAxMCYWEwgZ8wDQYJKoZIhvcN
AQEBBQADgY0AMIGJAoGBAMerInhZF/l0O0jmiD8M1lSSpHjFcT0peiwqWq+LZ8Ay
b6mcpnHdFVmHQaGtUt+6i+0NqKDppxnaVW4vOdYD64OlmSVrG+WzkYMAmE/0EzJN
A5pEA5ZK1w6MGo+IQLjrPDmm/qV6XrkARR2THjA2xKE8/L7s+VEJj/d+/CC8V7vP
AgMBAAGjgZYwgZMwHQYDVR0OBBYEFOHoipN0T0TNs1IwFkmTwLDtsV0gMGQGA1Ud
IwRdMFuAFOHoipN0T0TNs1IwFkmTwLDtsV0goTikNjA0MQswCQYDVQQGEwJhYTEL
MAkGA1UEChMCYWExCzAJBgNVBAsTAmFhMQswCQYDVQQDEwJhYYIJAPEn4h3J3p2d
MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEANTQgpYm+OBZTTYbLkyBH
MQ9QygwgNWOQJ9hEbT0xpiL8xHXBTQdHJkMXD/PWzs1AyZShXsUwcKBaKgxyIsQj
a36poKPyfAYbfsg8xLyijMVXbsW7OlKN9FjapaZTnEvHfsMO8ITAad4a7RVWAYQ8
ucT7nO9OPFjOv8dwGsF5RVM=
-----END CERTIFICATE-----
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</KeyDescriptor>
<SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="http://idp5/singleSignOn"/>
</IDPSSODescriptor>
</EntityDescriptor>
x = open('metadata.xml', 'w')
doc.writexml(x, " ", "", "\n", "UTF-8")
x.close()
2
那么,你的问题是什么呢?在这两行代码中:
>>> ptext = doc.createTextNode("This is a test!")
>>> x509cert.appendChild(ptext)
你实际上是在创建一个文本节点,它是节点 "<ds:X509Certificate>"
的一个子节点。这个文本节点的内容是 "This is a test!"。如果你想插入其他内容作为文本,你需要用合适的参数调用 .createTextNode 方法。
编辑(考虑到提问者的评论):不,这不是 文本内容。在 XML 中,所有东西都是节点。你认为的“标签之间的文本”,实际上是一个 文本节点。