¿Cómo consigo que Nokogiri entienda mis espacios de nombres?
Pregunta
Tengo el siguiente documento XML:
<samlp:LogoutRequest ID="123456789" Version="2.0" IssueInstant="200904051217">
<saml:NameID>@NOT_USED@</saml:NameID>
<samlp:SessionIndex>abcdefg</samlp:SessionIndex>
</samlp:LogoutRequest>
Me gustaría obtener el contenido del SessionIndex
(es decir, 'abcdefg'). He intentado esto:
XPATH_QUERY = "LogoutRequest[@ID][@Version='2.0'][IssueInstant]/SessionIndex"
SAML_XMLNS = 'urn:oasis:names:tc:SAML:2.0:assertion'
SAMLP_XMLNS = 'urn:oasis:names:tc:SAML:2.0:protocol'
require 'nokogiri'
doc = Nokogiri::XML(xml)
doc.xpath(XPATH_QUERY, 'saml' => SAML_XMLNS, 'samlp' => SAMLP_XMLNS)
pero obtengo los siguientes errores:
Nokogiri::XML::SyntaxError: Namespace prefix samlp on LogoutRequest is not defined
Nokogiri::XML::SyntaxError: Namespace prefix saml on NameID is not defined
Nokogiri::XML::SyntaxError: Namespace prefix samlp on SessionIndex is not defined
He intentado agregar los espacios de nombres a la consulta XPath, pero eso no cambia nada.
¿Por qué no puedo convencer a Nokogiri de que los espacios de nombres son válidos?
Solución
No parece que los espacios de nombres en este documento estén correctamente declarados; debe haber atributos xmlns: samlp
y xmlns: saml
en el nodo raíz. En casos como este, Nokogiri esencialmente ignora los espacios de nombres (ya que no puede asignarlos a URI o URN), por lo que su XPath funciona si los elimina, es decir,
doc.xpath(XPATH_QUERY)
Otros consejos
Veo dos opciones diferentes para usted:
-
Eliminar todos los espacios de nombres
Forma de fuerza bruta de hacerlo. Podría dar lugar a problemas donde hay colisiones de espacio de nombres.
-
Usar collect_namespaces
Una solución mucho mejor. Puede usar esto una vez para identificar los espacios de nombres (digamos en irb) y codificarlos.
O
Úselo en tiempo de ejecución y proporciónelo como el segundo argumento para https://www.rubydoc.info/github/sparklemotion/nokogiri/Nokogiri/XML/Searchable#xpath-instance_method