Как удалить пространства имен из 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);

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

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

Джош

Ответы

Ответ 1

Для узлов Element и Attribute:

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

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

См. Node.getLocalName()

Ответ 2

Используйте функцию 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 */
}

Ответ 3

Вместо

dbFactory_.setNamespaceAware(true);

Использование

dbFactory_.setNamespaceAware(false);

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


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

Ответ 4

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

Ответ 5

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

Ответ 6

Tomalak, одно исправление вашего XSLT (в третьем шаблоне):

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

Ответ 7

Размер входного xml также необходимо учитывать при выборе решения. Для больших xmls размером ~ 100k, возможно, если ваш вход от веб-службы, вам также нужно учитывать последствия сбора мусора при манипулировании большой строкой. Раньше мы использовали String.replaceAll, и это вызывало частые OOM в производстве с размером кучи 1.5G из-за того, как был реализован метод replaceAll.

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

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

Ответ 8

Вместо использования TransformerFactory и последующего вызова на него (который вводил пустое пространство имен, я преобразовал следующее:

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