【问题标题】:Java Transformer how to ignore namespacesJava Transformer如何忽略命名空间
【发布时间】:2015-06-18 14:28:20
【问题描述】:

我必须将 XML 转换为 XHTML,但 XML 定义了一个命名空间 xmlns='http://www.lotus.com/dxl',它从未在整个 XML 中使用,因此解析器不会解析任何内容...

有没有办法忽略命名空间?我正在使用 Oracle java 转换器import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory

或者有没有更好的库?

【问题讨论】:

    标签: java xml xslt


    【解决方案1】:

    不,你不能忽略命名空间。

    如果命名空间声明 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 处理器。因此,您必须以艰难的方式进行(在大约 10,000 篇文章中对此进行了描述,您可以通过搜索“XSLT 默认命名空间”找到这些文章)。

    【讨论】:

    • 非常感谢!这对我帮助很大。所以我必须找到使用默认命名空间的解决方法或使用另一个解析器。非常感谢!
    • @ATorras 如果这是真的,那么每个人都对此保持沉默。你的来源是什么?
    • Java 8 处理 XSLT 2.0 开箱即用,但我无法使“xpath-default-namespace”工作,所以我不得不使用@TimoKinnunen 指出的setNameSpaceAware(false)
    • @ATorras 对不起,但我认为你错了。
    • 如果在符合 XSLT 1.0 的处理器上运行指定 version="x" 且 x>1.0 的样式表,则处理器以“向前兼容模式”运行,这意味着它会忽略 XSLT 1.0 中不可用的属性,如xpath-default-namespace
    【解决方案2】:

    您不能轻易地忽略命名空间, 而且它不会很漂亮,但它是可能的。当然,将Transformer 实现中的正确部分欺骗为仅输出前缀而不感到慌张是实现依赖!

    好吧,这对我从 NodeStringWriter 有用:

    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 相互转换的方法:

    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;
    }
    

    【讨论】:

      猜你喜欢
      • 2011-12-05
      • 2015-02-18
      • 1970-01-01
      • 2011-05-25
      • 1970-01-01
      • 2015-05-01
      • 2014-04-10
      • 2023-03-11
      • 1970-01-01
      相关资源
      最近更新 更多