Как удалить пространства имен из xml, используя java dom?

у меня есть следующий код

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

но это не то, что я ищу, мне нужно что-то, чтобы полностью избавиться от пространств имен.

любая помощь будет оценили, Спасибо,

Джош

8 ответов


для узлов элементов и атрибутов:

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

даст вам локальную часть имени узла.

посмотреть узел.getLocalName()


используйте функцию Regex. Это решит эту проблему:

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

, а не

dbFactory_.setNamespaceAware(true);

использовать

dbFactory_.setNamespaceAware(false);

хотя я согласен с Tomalak: в общем, пространства имен являются более полезными, чем вредными. Почему ты не хочешь их использовать?


Edit: этот ответ не отвечает на вопрос OP, который заключался в том, как избавиться от пространства имен приставки. Rd01 предоставил правильный ответ на этот вопрос.


вы can предварительно обработайте 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 для этого должно быть много, даже на этом сайте. Полученный документ будет иметь точно такую же структуру и макет, только без пространств имен.


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

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>

размер входного XML также необходимо учитывать при выборе решения. Для больших xmls размером ~100k, возможно, если ваш ввод из веб-службы, вам также необходимо учитывать последствия сборки мусора при манипулировании большой строкой. Мы использовали строку.replaceAll раньше, и это вызвало частые ООМ в производстве с размером кучи 1,5 г из-за способа replaceAll реализуется.

можно ссылку http://app-inf.blogspot.com/2013/04/pitfalls-of-handling-large-string.html для наших выводов.

Я не уверен, как XSLT имеет дело с большими строковыми объектами, но мы закончили разбор строки вручную, чтобы удалить префиксы в одном разборе, чтобы избежать создания дополнительных больших объектов 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;
}

вместо использования 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();