如何解决Xalan-J:在扩展函数中解析QName文本值的名称空间
我已经实现了一个简单的XPath扩展功能,该功能旨在由Xalan-J在XSLT转换期间调用。调用部分很简单,但是我不明白的是,该函数的实现应该如何访问要转换的文档的名称空间上下文(不是转换的上下文,它是扩展函数的第一个参数)。我需要此上下文以便解析实际上是QName的元素文本值的命名空间。
这是一个需要转换的示例文档:
<document xmlns='org.stackoverflow.example.document'>
<element xmlns:value="org.stackoverflow.example.value">value:some-value</element>
</document>
value:some-value
是我要解析的QName文本值的示例-它表示some-value
命名空间中的org.stackoverflow.example.value
。
转换看起来像这样:
<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
xmlns:sofun='xalan://org.stackoverflow.example.XPathFunctionQNameTextValueResolver'
xmlns:doc='org.stackoverflow.example.document'>
<xsl:template match='/doc:document/doc:element'>
<xsl:value-of select='sofun:resolveQNameTextValue(.)' />
</xsl:template>
</xsl:stylesheet>
它实际上只是使用节点element
作为唯一参数调用扩展函数。
因此实际的代码如下所示(在类路径中需要Xalan-J 2.7.1):
package org.stackoverflow.example;
import java.io.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import org.apache.xalan.extensions.ExpressionContext;
import org.w3c.dom.NamednodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.traversal.NodeIterator;
public class XPathFunctionQNameTextValueResolver {
public static final boolean resolveQNameTextValue(ExpressionContext ctx,NodeIterator nodes) {
Node node = nodes.nextNode();
while (node != null) {
if (node.hasChildNodes()) {
String textValue = node.getFirstChild().getNodeValue();
String[] pfxAndName = textValue.split(":");
String prefix = "";
String name = textValue;
if (pfxAndName.length == 2) {
prefix = pfxAndName[0];
name = pfxAndName[1];
}
String namespace = node.lookupNamespaceURI(prefix);
// "namespace" is always null,unless null is supplied as "prefix",which returns the default namespace
NamednodeMap attributes = node.getAttributes();
if (attributes != null) {
// "attributes" does not contain any "xmlns" attributes
}
System.out.println(
String.format(
"namespace: %s,prefix:%s,local-name: %s,attributes-len: %d",namespace,prefix,name,attributes != null ? attributes.getLength() : 0));
}
node = nodes.nextNode();
}
return false;
}
public static void main(String[] args) throws TransformerConfigurationException,TransformerException {
String xslt = "" +
"<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform'\n" +
" xmlns:sofun='xalan://org.stackoverflow.example.XPathFunctionQNameTextValueResolver'\n" +
" xmlns:doc='org.stackoverflow.example.document'>\n" +
" <xsl:template match='/doc:document/doc:element'>\n" +
" <xsl:value-of select='sofun:resolveQNameTextValue(.)' />\n" +
" </xsl:template>\n" +
"</xsl:stylesheet>";
String document = "" +
"<document xmlns='org.stackoverflow.example.document'>\n" +
" <element xmlns:value=\"org.stackoverflow.example.value\">value:some-value</element>\n" +
"</document>";
TransformerFactory xalanTransFact = new org.apache.xalan.processor.TransformerFactoryImpl();
Templates template = xalanTransFact.newTemplates(new StreamSource(new StringReader(xslt)));
StringWriter writer = new StringWriter();
Transformer transformer = template.newTransformer();
transformer.transform(new StreamSource(new StringReader(document)),new StreamResult(writer));
}
}
期望node.lookupNamespaceURI(prefix)
将提供我需要的名称空间,但事实并非如此。 node
实际上是DOM模型中的一个节点,但是这些节点似乎不包含任何名称空间信息。就像生成这些节点的解析器配置错误并完全忽略名称空间一样。
如何更改示例,以便在运行时执行XPath函数的实现时出现名称空间信息?
解决方法
根据@MartinHonnen在评论中的建议,如果需要命名空间,则需要自己提供一个了解命名空间的输入文档解析器:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document parse = builder.parse(new InputSource(new StringReader(document)));
transformer.transform(new DOMSource(parse),new StreamResult(writer));
更正的示例:
package org.stackoverflow.example;
import java.io.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.*;
import org.apache.xalan.extensions.ExpressionContext;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.traversal.NodeIterator;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class XPathFunctionQNameTextValueResolver {
public static final boolean resolveQNameTextValue(ExpressionContext ctx,NodeIterator nodes) {
Node node = nodes.nextNode();
while (node != null) {
if (node.hasChildNodes()) {
String textValue = node.getFirstChild().getNodeValue();
String[] pfxAndName = textValue.split(":");
String prefix = "";
String name = textValue;
if (pfxAndName.length == 2) {
prefix = pfxAndName[0];
name = pfxAndName[1];
}
String namespace = node.lookupNamespaceURI(prefix);
// "namespace" is always null,unless null is supplied as "prefix",which returns the default namespace
NamedNodeMap attributes = node.getAttributes();
if (attributes != null) {
// "attributes" does not contain any "xmlns" attributes
}
System.out.println(
String.format(
"namespace: %s,prefix:%s,local-name: %s,attributes-len: %d",namespace,prefix,name,attributes != null ? attributes.getLength() : 0));
}
node = nodes.nextNode();
}
return false;
}
public static void main(String[] args) throws TransformerConfigurationException,TransformerException,ParserConfigurationException,IOException,SAXException {
String xslt = "" +
"<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform'\n" +
" xmlns:sofun='xalan://org.stackoverflow.example.XPathFunctionQNameTextValueResolver'\n" +
" xmlns:doc='org.stackoverflow.example.document'>\n" +
" <xsl:template match='/doc:document/doc:element'>\n" +
" <xsl:value-of select='sofun:resolveQNameTextValue(.)' />\n" +
" </xsl:template>\n" +
"</xsl:stylesheet>";
String document = "" +
"<document xmlns='org.stackoverflow.example.document'>\n" +
" <element xmlns:value=\"org.stackoverflow.example.value\">value:some-value</element>\n" +
"</document>";
TransformerFactory xalanTransFact = new org.apache.xalan.processor.TransformerFactoryImpl();
Templates template = xalanTransFact.newTemplates(new StreamSource(new StringReader(xslt)));
StringWriter writer = new StringWriter();
Transformer transformer = template.newTransformer();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document parse = builder.parse(new InputSource(new StringReader(document)));
transformer.transform(new DOMSource(parse),new StreamResult(writer));
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。