首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Xalan-J:在扩展函数中解析QName文本值的名称空间

Xalan-J:在扩展函数中解析QName文本值的名称空间
EN

Stack Overflow用户
提问于 2020-11-09 17:09:13
回答 1查看 99关注 0票数 1

我已经实现了一个简单的XPath扩展函数,该函数将在XSLT转换期间由Xalan-J调用。调用部分很简单,但我不理解的是,函数的实现如何访问被转换文档的名称空间上下文(而不是转换上下文,作为扩展函数的第一个参数提供)。我需要这个上下文来解析实际为QNames的元素文本值的名称空间。

下面是一个需要转换的示例文档:

代码语言:javascript
复制
<document xmlns='org.stackoverflow.example.document'>
    <element xmlns:value="org.stackoverflow.example.value">value:some-value</element>
</document>

value:some-value是我想要解析的QName文本值的一个例子-它表示org.stackoverflow.example.value名称空间中的some-value

转换过程如下所示:

代码语言:javascript
复制
<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 ):

代码语言:javascript
复制
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函数时显示名称空间信息?

EN

回答 1

Stack Overflow用户

发布于 2020-11-09 17:33:12

根据@MartinHonnen在评论中的建议,如果您需要名称空间,您需要自己提供一个支持名称空间的输入文档解析器:

代码语言:javascript
复制
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));

更正示例:

代码语言:javascript
复制
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));
    }
    
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64748688

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档