获取带命名空间的XML节点的最简方法是什么?
嘿,这个问题的核心在于处理XML的默认命名空间——你的XML里根节点声明了xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd",所有子节点都默认属于这个命名空间,直接用节点名查询是找不到的。下面给几个主流编程语言的最简实现,你可以对应自己的场景来用:
Python(标准库xml.etree.ElementTree)
注册一个命名空间前缀,然后用带前缀的XPath查询即可,这是最省事儿的标准库方案:
import xml.etree.ElementTree as ET # 你的XML内容 xml_content = '''<?xml version="1.0" encoding="UTF-8"?> <createTransactionResponse xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <messages> <resultCode>Ok</resultCode> <message> <code>I00001</code> <text>Successful.</text> </message> </messages> <transactionResponse> <responseCode>1</responseCode> </transactionResponse> </createTransactionResponse>''' # 注册命名空间前缀(比如叫"anet") ET.register_namespace('anet', 'AnetApi/xml/v1/schema/AnetApiSchema.xsd') root = ET.fromstring(xml_content) # 用带前缀的XPath查询节点 result_code = root.find('.//anet:resultCode', namespaces={'anet': 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'}) print(result_code.text) # 输出: Ok # 查询transactionResponse下的responseCode response_code = root.find('.//anet:transactionResponse/anet:responseCode', namespaces={'anet': 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'}) print(response_code.text) # 输出: 1
C#(LINQ to XML,最简写法)
如果用LINQ to XML,直接绑定命名空间后拼接节点名就行,代码非常简洁:
using System.Xml.Linq; var xmlContent = @"<?xml version=""1.0"" encoding=""UTF-8""?> <createTransactionResponse xmlns=""AnetApi/xml/v1/schema/AnetApiSchema.xsd"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance""> <messages> <resultCode>Ok</resultCode> <message> <code>I00001</code> <text>Successful.</text> </message> </messages> <transactionResponse> <responseCode>1</responseCode> </transactionResponse> </createTransactionResponse>"; // 绑定命名空间 XNamespace anetNs = "AnetApi/xml/v1/schema/AnetApiSchema.xsd"; XDocument doc = XDocument.Parse(xmlContent); // 直接查询节点 var resultCode = doc.Descendants(anetNs + "resultCode").First().Value; Console.WriteLine(resultCode); // 输出: Ok var responseCode = doc.Descendants(anetNs + "transactionResponse") .Elements(anetNs + "responseCode") .First().Value; Console.WriteLine(responseCode); // 输出: 1
Java(标准库XPath)
通过NamespaceContext绑定前缀,再用XPath查询,这是Java标准库的最简方式:
import javax.xml.xpath.*; import org.w3c.dom.*; import org.xml.sax.InputSource; import java.io.StringReader; import java.util.Iterator; public class XmlNamespaceDemo { public static void main(String[] args) throws Exception { String xmlContent = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<createTransactionResponse xmlns=\"AnetApi/xml/v1/schema/AnetApiSchema.xsd\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" + " <messages>\n" + " <resultCode>Ok</resultCode>\n" + " <message>\n" + " <code>I00001</code>\n" + " <text>Successful.</text>\n" + " </message>\n" + " </messages>\n" + " <transactionResponse>\n" + " <responseCode>1</responseCode>\n" + " </transactionResponse>\n" + "</createTransactionResponse>"; XPath xpath = XPathFactory.newInstance().newXPath(); // 设置命名空间映射 xpath.setNamespaceContext(new NamespaceContext() { @Override public String getNamespaceURI(String prefix) { return "anet".equals(prefix) ? "AnetApi/xml/v1/schema/AnetApiSchema.xsd" : null; } @Override public String getPrefix(String uri) { return null; } @Override public Iterator getPrefixes(String uri) { return null; } }); // 查询节点 InputSource source = new InputSource(new StringReader(xmlContent)); String resultCode = xpath.evaluate("//anet:resultCode", source); System.out.println(resultCode); // 输出: Ok String responseCode = xpath.evaluate("//anet:transactionResponse/anet:responseCode", source); System.out.println(responseCode); // 输出: 1 } }
核心总结
不管用什么语言,必须显式关联节点和它的命名空间,不能直接用裸节点名查询。最简逻辑都是:
- 给目标命名空间绑定一个简短前缀
- 用「前缀:节点名」的格式进行查询或节点定位
内容的提问来源于stack exchange,提问作者HerrimanCoder
相关产品推荐
相关产品推荐

