XmlDocument创建仅含命名空间前缀元素的问题(X++/.NET)
我需要生成如下结构的XML(根标签为<CBIBdyPaymentRequest>),要求<PMRQ:GrpHdr>仅保留PMRQ前缀,不要附加xmlns:PMRQ="urn:CBI:xsd:CBIBdyPaymentRequest.00.04.01"属性:
<?xml version="1.0" encoding="UTF-8"?> <CBIBdyPaymentRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:CBI:xsd:CBIBdyPaymentRequest.00.04.01 CBIBdyPaymentRequest.00.04.01.xsd" xmlns:PMRQ="urn:CBI:xsd:CBIPaymentRequest.00.04.01" xmlns="urn:CBI:xsd:CBIBdyPaymentRequest.00.04.01"> <CBIEnvelPaymentRequest> <CBIPaymentRequest> <PMRQ:GrpHdr>
但当前用X++生成的XML里,<PMRQ:GrpHdr>和<PMRQ:PmtInf>自动带上了额外的命名空间声明,而它们的子标签却没有这个问题:
<?xml version="1.0" encoding="UTF-8"?> <CBIBdyPaymentRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:CBI:xsd:CBIBdyPaymentRequest.00.04.01 CBIBdyPaymentRequest.00.04.01.xsd" xmlns:PMRQ="urn:CBI:xsd:CBIPaymentRequest.00.04.01" xmlns="urn:CBI:xsd:CBIBdyPaymentRequest.00.04.01"> <CBIEnvelPaymentRequest> <CBIPaymentRequest> <PMRQ:GrpHdr xmlns:PMRQ="urn:CBI:xsd:CBIBdyPaymentRequest.00.04.01"> <PMRQ:MsgId>G182581</PMRQ:MsgId> [...] </PMRQ:GrpHdr> <PMRQ:PmtInf xmlns:PMRQ="urn:CBI:xsd:CBIBdyPaymentRequest.00.04.01"> <PMRQ:PmtMtd>TRF</PMRQ:PmtMtd> </PMRQ:PmtInf> </CBIPaymentRequest> </CBIEnvelPaymentRequest> </CBIBdyPaymentRequest>
我的测试代码如下:
xmlDoc = new XmlDocument(); xmlDoc.appendChild(xmlDoc.createProcessingInstruction("xml", 'version="1.0" encoding="UTF-8"')); nodeRoot = xmlDoc.appendChild(xmlDoc.createElement('CBIBdyPaymentRequest')); //1. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 属性 nodeRoot.setAttribute("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance"); //2. xsi:schemaLocation 属性 schemaLocationAttribute = xmlDoc.createAttribute2("xsi:schemaLocation", "http://www.w3.org/2001/XMLSchema-instance"); schemaLocationAttribute.value('urn:CBI:xsd:CBIBdyPaymentRequest.00.04.01 CBIBdyPaymentRequest.00.04.01.xsd'); nodeRoot.setAttributeNode(schemaLocationAttribute); //3. xmlns:PMRQ="urn:CBI:xsd:CBIPaymentRequest.00.04.01" 属性 nodeRoot.setAttribute("xmlns:PMRQ","urn:CBI:xsd:CBIPaymentRequest.00.04.01"); //4. 默认命名空间 xmlns="urn:CBI:xsd:CBIBdyPaymentRequest.00.04.01" nodeRoot.setAttribute("xmlns","urn:CBI:xsd:CBIBdyPaymentRequest.00.04.01"); nodeRoot2 = nodeRoot.appendChild(xmlDoc.createElement('CBIEnvelPaymentRequest')); nodeRoot3 = nodeRoot2.appendChild(xmlDoc.createElement('CBIPaymentRequest')); nodeRoot3.prefix("PMRQ"); nodeGrpHdr = nodeRoot3.appendChild(xmlDoc.createElement3("PMRQ", "GrpHdr","urn:CBI:xsd:CBIBdyPaymentRequest.00.04.01")); //msgId xeTmp = nodeGrpHdr.appendChild(xmlDoc.createElement3("PMRQ","MsgId","urn:CBI:xsd:CBIBdyPaymentRequest.00.04.01")); xeTmp.appendChild(xmlDoc.createTextNode("test string")); xeTmp = nodeGrpHdr.appendChild(xmlDoc.createElement3("PMRQ","Tmp","urn:CBI:xsd:CBIBdyPaymentRequest.00.04.01")); xeTmp.appendChild(xmlDoc.createTextNode("test string")); nodeGrpHdr2 = nodeRoot3.appendChild(xmlDoc.createElement3("PMRQ", "GrpHdr2","urn:CBI:xsd:CBIBdyPaymentRequest.00.04.01")); xeTmp = nodeGrpHdr2.appendChild(xmlDoc.createElement3("PMRQ","MsgId2","urn:CBI:xsd:CBIBdyPaymentRequest.00.04.01")); xeTmp.appendChild(xmlDoc.createTextNode("test string"));
为什么用相同的创建方法,<PMRQ:GrpHdr>会带上额外的命名空间声明,而其子标签不会?如何让<PMRQ:GrpHdr>只保留前缀,不附加该属性?
问题原因
你在根节点声明的PMRQ命名空间是urn:CBI:xsd:CBIPaymentRequest.00.04.01,但创建<PMRQ:GrpHdr>等标签时,传入的命名空间却是urn:CBI:xsd:CBIBdyPaymentRequest.00.04.01(和根节点的默认命名空间一致)。XML解析器发现当前标签使用的PMRQ前缀对应的命名空间,和上级节点声明的PMRQ命名空间不匹配,就会自动在当前标签上重新声明这个前缀对应的新命名空间。
而子标签(比如<PMRQ:MsgId>)之所以没有额外声明,是因为它们继承了父标签<PMRQ:GrpHdr>上重新声明的命名空间,不需要再重复添加。
解决方案
创建PMRQ前缀的标签时,使用和根节点一致的PMRQ命名空间值,也就是urn:CBI:xsd:CBIPaymentRequest.00.04.01,替换掉代码中createElement3的第三个参数。
修改后的关键代码片段:
// 使用根节点声明的PMRQ命名空间 nodeGrpHdr = nodeRoot3.appendChild(xmlDoc.createElement3("PMRQ", "GrpHdr","urn:CBI:xsd:CBIPaymentRequest.00.04.01")); //msgId xeTmp = nodeGrpHdr.appendChild(xmlDoc.createElement3("PMRQ","MsgId","urn:CBI:xsd:CBIPaymentRequest.00.04.01")); xeTmp.appendChild(xmlDoc.createTextNode("test string")); xeTmp = nodeGrpHdr.appendChild(xmlDoc.createElement3("PMRQ","Tmp","urn:CBI:xsd:CBIPaymentRequest.00.04.01")); xeTmp.appendChild(xmlDoc.createTextNode("test string")); nodeGrpHdr2 = nodeRoot3.appendChild(xmlDoc.createElement3("PMRQ", "GrpHdr2","urn:CBI:xsd:CBIPaymentRequest.00.04.01")); xeTmp = nodeGrpHdr2.appendChild(xmlDoc.createElement3("PMRQ","MsgId2","urn:CBI:xsd:CBIPaymentRequest.00.04.01")); xeTmp.appendChild(xmlDoc.createTextNode("test string"));
修改后生成的XML
<?xml version="1.0" encoding="UTF-8"?> <CBIBdyPaymentRequest xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:CBI:xsd:CBIBdyPaymentRequest.00.04.01 CBIBdyPaymentRequest.00.04.01.xsd" xmlns:PMRQ="urn:CBI:xsd:CBIPaymentRequest.00.04.01" xmlns="urn:CBI:xsd:CBIBdyPaymentRequest.00.04.01"> <CBIEnvelPaymentRequest> <CBIPaymentRequest> <PMRQ:GrpHdr> <PMRQ:MsgId>test string</PMRQ:MsgId> <PMRQ:Tmp>test string</PMRQ:Tmp> </PMRQ:GrpHdr> <PMRQ:GrpHdr2> <PMRQ:MsgId2>test string</PMRQ:MsgId2> </PMRQ:GrpHdr2> </CBIPaymentRequest> </CBIEnvelPaymentRequest> </CBIBdyPaymentRequest>
内容的提问来源于stack exchange,提问作者Win32

