我必须将XML转换为XHTML,但XML定义了一个名称空间xmlns='http://www.lotus.com/dxl'
,它从未在整个XML中使用,因此解析器不会解析任何内容......
有没有办法忽略namepsaces?我正在使用Oracle java转换器import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory
或者有更好的图书馆吗?
答案 0 :(得分:3)
不,你不能忽略命名空间。
如果名称空间声明xmlns =' http://www.lotus.com/dxl'出现在最外面的元素中,那么你就无法说它并没有在任何地方使用过。" - 相反,它无处不在!它有效地将文档中的每个元素名称更改为不同的名称。你无法忽视这一点。
如果您使用的是XSLT 2.0,那么您可以在样式表xpath-default-namespace="http://www.lotus.com/dxl"
中说出几乎可以满足您的需求:它表示匹配模式或XPath表达式中任何未加前缀的名称都应该被解释引用命名空间http://www.lotus.com/dxl中的名称。遗憾的是,您选择了一台未实现XSLT 2.0的XSLT处理器。因此,您必须采取艰难的方式(通过搜索" XSLT默认命名空间"将在大约10,000个帖子中描述)。
答案 1 :(得分:3)
你不能轻易地忽略名称空间,并且它不会很漂亮,但它是可能的。当然,在Transformer
实现中欺骗正确的部分只是输出前缀而不会感到慌张依赖于实现!
好的,这适合我从Node
转到StringWriter
:
public static String nodeToString(Node node) throws TransformerException {
StringWriter results = new StringWriter();
Transformer transformer = createTransformer();
transformer.transform(new DOMSource(node), new StreamResult(results) {
@Override
public Writer getWriter() {
Field field = findFirstAssignable(transformer.getClass());
try {
field.setAccessible(true);
field.set(transformer, new TransletOutputHandlerFactory(false) {
@Override
public SerializationHandler getSerializationHandler() throws
IOException, ParserConfigurationException {
SerializationHandler handler = super.getSerializationHandler();
SerializerBase base = (SerializerBase) handler.asDOMSerializer();
base.setNamespaceMappings(new NamespaceMappings() {
@Override
public String lookupNamespace(String prefix) {
return prefix;
}
});
return handler;
}
});
} catch(IllegalAccessException e) {
throw new AssertionError("Must not happen", e);
}
return super.getWriter();
}
});
return results.toString();
}
private static <E> Field findFirstAssignable(Class<E> clazz) {
return Stream.<Class<? super E>>iterate(clazz, Convert::iteration)
.flatMap(Convert::classToFields)
.filter(Convert::canAssign).findFirst().get();
}
private static <E> Class<? super E> iteration(Class<? super E> c) {
return c == null ? null : c.getSuperclass();
}
private static boolean canAssign(Field f) {
return f == null ||
f.getType().isAssignableFrom(TransletOutputHandlerFactory.class);
}
private static <E> Stream<Field> classToFields(Class<? super E> c) {
return c == null ? Stream.of((Field) null) :
Arrays.stream(c.getDeclaredFields());
}
这样做几乎就是自定义名称空间到前缀的映射。每个前缀都映射到由其前缀标识的命名空间,因此不应该有任何冲突。剩下的就是与API斗争。
为了使示例完整,以下是转换为XML和从XML转换的方法:
public static Transformer createTransformer()
throws TransformerFactoryConfigurationError,
TransformerConfigurationException {
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.INDENT, "no");
return transformer;
}
public static ArrayList<Node> parseNodes(String uri, String expression)
throws ParserConfigurationException, SAXException,
IOException,XPathExpressionException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(false);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(uri);
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
XPathExpression expr = xpath.compile(expression);
NodeList nl = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
ArrayList<Node> nodes = new ArrayList<>();
for(int i = 0; i < nl.getLength(); i++) {
nodes.add(nl.item(i));
}
return nodes;
}