如何使用java dom从xml中删除命名空间?

时间:2011-01-11 18:22:54

标签: java xml dom domdocument xml-namespaces

我有以下代码

DocumentBuilderFactory dbFactory_ = DocumentBuilderFactory.newInstance();
Document doc_;
DocumentBuilder dBuilder = dbFactory_.newDocumentBuilder();
StringReader reader = new StringReader(s);
InputSource inputSource = new InputSource(reader);
doc_ = dBuilder.parse(inputSource);
doc_.getDocumentElement().normalize();

然后我可以做

doc_.getDocumentElement();

并获取我的第一个元素,但问题不在于job元素是tns:job

我知道并试图使用:

dbFactory_.setNamespaceAware(true);

但这不是我想要的,我需要一些东西来完全摆脱命名空间。

任何帮助将不胜感激, 谢谢,

约什

9 个答案:

答案 0 :(得分:10)

使用Regex功能。这将解决这个问题:

public static String removeXmlStringNamespaceAndPreamble(String xmlString) {
  return xmlString.replaceAll("(<\\?[^<]*\\?>)?", ""). /* remove preamble */
  replaceAll("xmlns.*?(\"|\').*?(\"|\')", "") /* remove xmlns declaration */
  .replaceAll("(<)(\\w+:)(.*?>)", "$1$3") /* remove opening tag prefix */
  .replaceAll("(</)(\\w+:)(.*?>)", "$1$3"); /* remove closing tags prefix */
}

答案 1 :(得分:4)

对于元素和属性节点:

Node node = ...;
String name = node.getLocalName();

将为您提供节点名称的本地部分。

请参阅Node.getLocalName()

答案 2 :(得分:3)

而不是

dbFactory_.setNamespaceAware(true);

使用

dbFactory_.setNamespaceAware(false);

虽然我同意Tomalak:一般来说,命名空间比有害更有帮助。你为什么不想使用它们?


编辑:这个答案没有回答OP的问题,即如何摆脱命名空间前缀。 RD01提供了正确答案。

答案 3 :(得分:3)

如果您绝对必须这样做,可以预处理XML以删除所有名称空间。我建议不要这样做,因为从XML文档中删除命名空间实际上与从编程框架或库中删除命名空间相当 - 冒着名称冲突的风险,并且无法区分曾经不同的元素。但是,这是你的葬礼。 ; - )

此XSLT转换将从任何XML文档中删除所有名称空间。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="node()">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*">
    <xsl:element name="{local-name()}">
      <xsl:apply-templates select="node()|@*" />
    </xsl:element>
  </xsl:template>

  <xsl:template match="@*">
    <xsl:attribute name="{local-name()}">
      <xsl:apply-templates select="node()|@*" />
    </xsl:attribute>
  </xsl:template>
</xsl:stylesheet>

将其应用于XML文档。即使在这个网站上,做这样的事情的Java例子应该很多。生成的文档将完全具有相同的结构和布局,只是没有命名空间。

答案 4 :(得分:2)

public static void wipeRootNamespaces(Document xml) {       
    Node root = xml.getDocumentElement();
    NodeList rootchildren = root.getChildNodes();
    Element newroot = xml.createElement(root.getNodeName());

    for (int i=0;i<rootchildren.getLength();i++) {
        newroot.appendChild(rootchildren.item(i).cloneNode(true));
    }

    xml.replaceChild(newroot, root);
}

答案 5 :(得分:1)

Tomalak,XSLT的一个修复(在第3个模板中):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="node()">
    <xsl:copy>
        <xsl:apply-templates select="node() | @*" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*">
    <xsl:element name="{local-name()}">
        <xsl:apply-templates select="node() | @*" />
    </xsl:element>
  </xsl:template>

  <xsl:template match="@*">
    <!-- Here! -->
    <xsl:copy>
      <xsl:apply-templates select="node() | @*" />
    </xsl:copy>

  </xsl:template>
</xsl:stylesheet>

答案 6 :(得分:1)

选择解决方案时还需要考虑输入xml的大小。对于大型xmls,大小约为100k,如果您的输入来自Web服务,则还需要考虑操作大型字符串时的垃圾收集含义。之前我们使用过String.replaceAll,并且由于replaceAll的实现方式,它在生产中导致了1.5G堆大小的频繁OOM。

您可以参考http://app-inf.blogspot.com/2013/04/pitfalls-of-handling-large-string.html了解我们的发现。

我不确定XSLT如何处理大型String对象,但我们最终解析了字符串manualy以在一个解析中删除前缀以避免创建其他大型java对象。

public static String removePrefixes(String input1) {
    String ret = null;
    int strStart = 0;
    boolean finished = false;
    if (input1 != null) {
        //BE CAREFUL : allocate enough size for StringBuffer to avoid expansion
        StringBuffer sb = new StringBuffer(input1.length()); 
        while (!finished) {

            int start = input1.indexOf('<', strStart);
            int end = input1.indexOf('>', strStart);
            if (start != -1 && end != -1) {
                // Appending anything before '<', including '<'
                sb.append(input1, strStart, start + 1);

                String tag = input1.substring(start + 1, end);
                if (tag.charAt(0) == '/') {
                    // Appending '/' if it is "</"
                    sb.append('/');
                    tag = tag.substring(1);
                }

                int colon = tag.indexOf(':');
                int space = tag.indexOf(' ');
                if (colon != -1 && (space == -1 || colon < space)) {
                    tag = tag.substring(colon + 1);
                }
                // Appending tag with prefix removed, and ">"
                sb.append(tag).append('>');
                strStart = end + 1;
            } else {
                finished = true;
            }
        }
        //BE CAREFUL : use new String(sb) instead of sb.toString for large Strings
        ret = new String(sb);
    }
    return ret;
}

答案 7 :(得分:0)

而不是使用TransformerFactory然后调用它上面的transform(它注入了空名称空间,我转换如下:

    OutputStream outputStream = new FileOutputStream(new File(xMLFilePath));
    OutputFormat outputFormat = new OutputFormat(doc, "UTF-8", true);
    outputFormat.setOmitComments(true);
    outputFormat.setLineWidth(0);

    XMLSerializer serializer = new XMLSerializer(outputStream, outputFormat);
    serializer.serialize(doc);
    outputStream.close();

答案 8 :(得分:0)

我也遇到了命名空间问题,无法读取Java中的XML文件。解决方法如下:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(false);// this is imp code that will deactivate namespace in xml
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse("XML/"+ fileName);