XPath 命名空间绑定在将其构建为文档后丢失
XPath namepsace binding is lost after building it as document
我正在尝试对 xml 格式的字符串进行 Xpath 查询。使用 javax.xml 库
这是我的代码(这段代码可能看起来很奇怪,因为我使用的是 scala。我将 java 代码转换为 scala 代码):
import javax.xml.xpath._
import org.xml.sax.InputSource
import java.io.StringReader
import javax.xml.parsers._
import javax.xml.transform.dom.DOMSource
import java.io.StringWriter
import javax.xml.transform.stream.StreamResult
import javax.xml.transform.TransformerFactory
import javax.xml.namespace.NamespaceContext
import java.io.ByteArrayInputStream
import org.w3c.dom._
import java.util.Iterator
import javax.xml._
import org.apache.ws.commons.util.NamespaceContextImpl
val sampleXML = """<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"/>
<soap:Body>
<ns2:CreateTransactionResponse xmlns:ns2="http://testing.xml.ph/provisioning/1">
<status>404</status>
<reason>not found</reason>
</ns2:CreateTransactionResponse>
</soap:Body>
</soap:Envelope>"""
val inputSource = new InputSource(new StringReader(sampleXML))
var personalNameSpace = new NamespaceContextImpl
personalNameSpace.startPrefixMapping("soap", "http://schemas.xmlsoap.org/soap/envelope/")
personalNameSpace.startPrefixMapping("SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/")
personalNameSpace.startPrefixMapping("ns2", "http://testing.xml.ph/provisioning/1")
var factory = XPathFactory.newInstance()
var xpath = factory.newXPath()
xpath.setNamespaceContext(personalNameSpace)
//To check whether or not the namespace is properly binded in the xpath.
//And it is. This one returns "PREFIX : SOAP-ENV"
println("PREFIX : " + xpath.getNamespaceContext.getPrefix("http://schemas.xmlsoap.org/soap/envelope/"))
var dbf = DocumentBuilderFactory.newInstance()
var docbuild = dbf.newDocumentBuilder()
var document = docbuild.parse(inputSource)
val testExtract = xpath.evaluate("/*[local-name() = 'Envelope']/soap:Body", document, XPathConstants.NODESET).asInstanceOf[NodeList]
println(s"testExtractSize : ${testExtract.getLength}") // Returns 0
for(index <- 0 until testExtract.getLength) {
val node = testExtract.item(index)
println(s"Node Text Content: ${node.getTextContent}")
println(s"Node LocalName: ${node.getLocalName}")
println(s"Node Prefix: ${node.getPrefix}")
}
但是当我不将其更改为文档而只是在我的 xpath 中使用 inputSource 时。它正确 returns 我需要的一切 :
val testExtract = xpath.evaluate("/*[local-name() = 'Envelope']/soap:Body", inputSource, XPathConstants.NODESET).asInstanceOf[NodeList]
我得到了正确的日志:
Node Text Content:
404
not found
Node LocalName: Body
Node Prefix: soap
为什么要改成文档?因为我需要重用它。而 InputSource 不会这样做。我需要重新初始化它。
此致
确保你做到了
var dbf = DocumentBuilderFactory.newInstance()
dbf.setNamespaceAware(true);
在对 DOM 文档进行任何 XSLT/XPath 操作之前。
我正在尝试对 xml 格式的字符串进行 Xpath 查询。使用 javax.xml 库
这是我的代码(这段代码可能看起来很奇怪,因为我使用的是 scala。我将 java 代码转换为 scala 代码):
import javax.xml.xpath._
import org.xml.sax.InputSource
import java.io.StringReader
import javax.xml.parsers._
import javax.xml.transform.dom.DOMSource
import java.io.StringWriter
import javax.xml.transform.stream.StreamResult
import javax.xml.transform.TransformerFactory
import javax.xml.namespace.NamespaceContext
import java.io.ByteArrayInputStream
import org.w3c.dom._
import java.util.Iterator
import javax.xml._
import org.apache.ws.commons.util.NamespaceContextImpl
val sampleXML = """<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"/>
<soap:Body>
<ns2:CreateTransactionResponse xmlns:ns2="http://testing.xml.ph/provisioning/1">
<status>404</status>
<reason>not found</reason>
</ns2:CreateTransactionResponse>
</soap:Body>
</soap:Envelope>"""
val inputSource = new InputSource(new StringReader(sampleXML))
var personalNameSpace = new NamespaceContextImpl
personalNameSpace.startPrefixMapping("soap", "http://schemas.xmlsoap.org/soap/envelope/")
personalNameSpace.startPrefixMapping("SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/")
personalNameSpace.startPrefixMapping("ns2", "http://testing.xml.ph/provisioning/1")
var factory = XPathFactory.newInstance()
var xpath = factory.newXPath()
xpath.setNamespaceContext(personalNameSpace)
//To check whether or not the namespace is properly binded in the xpath.
//And it is. This one returns "PREFIX : SOAP-ENV"
println("PREFIX : " + xpath.getNamespaceContext.getPrefix("http://schemas.xmlsoap.org/soap/envelope/"))
var dbf = DocumentBuilderFactory.newInstance()
var docbuild = dbf.newDocumentBuilder()
var document = docbuild.parse(inputSource)
val testExtract = xpath.evaluate("/*[local-name() = 'Envelope']/soap:Body", document, XPathConstants.NODESET).asInstanceOf[NodeList]
println(s"testExtractSize : ${testExtract.getLength}") // Returns 0
for(index <- 0 until testExtract.getLength) {
val node = testExtract.item(index)
println(s"Node Text Content: ${node.getTextContent}")
println(s"Node LocalName: ${node.getLocalName}")
println(s"Node Prefix: ${node.getPrefix}")
}
但是当我不将其更改为文档而只是在我的 xpath 中使用 inputSource 时。它正确 returns 我需要的一切 :
val testExtract = xpath.evaluate("/*[local-name() = 'Envelope']/soap:Body", inputSource, XPathConstants.NODESET).asInstanceOf[NodeList]
我得到了正确的日志:
Node Text Content:
404
not found
Node LocalName: Body
Node Prefix: soap
为什么要改成文档?因为我需要重用它。而 InputSource 不会这样做。我需要重新初始化它。
此致
确保你做到了
var dbf = DocumentBuilderFactory.newInstance()
dbf.setNamespaceAware(true);
在对 DOM 文档进行任何 XSLT/XPath 操作之前。