Как мне удалить пространства имен из XML, используя Java DOM? - PullRequest
12 голосов
/ 11 января 2011

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

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 ]

10 голосов
/ 07 июля 2011

Используйте функцию 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 */
}
4 голосов
/ 11 января 2011

Для узлов Элемента и Атрибута:

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

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

См. Node.getLocalName ()

3 голосов
/ 11 января 2011

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

3 голосов
/ 11 января 2011

Вместо

dbFactory_.setNamespaceAware(true);

Используйте

dbFactory_.setNamespaceAware(false);

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


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

2 голосов
/ 14 мая 2013
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);
}
1 голос
/ 14 апреля 2013

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

Вы можете ссылаться на наши выводы http://app -inf.blogspot.com / 2013/04 / pitfalls-of-processing-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;
}
1 голос
/ 13 декабря 2011

Томалак, одно исправление вашего 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>
0 голосов
/ 21 января 2015

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