كيفية تجاهل المسافة البيضاء أثناء قراءة ملف لإنتاج XML DOM

StackOverflow https://stackoverflow.com/questions/229310

  •  04-07-2019
  •  | 
  •  

سؤال

أحاول قراءة ملف لإنتاج مستند DOM ، لكن الملف يحتوي على مساحة بيضاء وخطوط جديدة وأحاول تجاهلها ، لكنني لم أستطع:

DocumentBuilderFactory docfactory=DocumentBuilderFactory.newInstance();
docfactory.setIgnoringElementContentWhitespace(true);

أرى في Javadoc أن طريقة setInoringElementContentWhiteSpace لا تعمل إلا عند تمكين علامة التحقق من التحقق ، لكنني لست مخطط DTD أو XML للوثيقة.

ماذا يمكنني أن أفعل؟

تحديث

لا أحب فكرة تقديم نفسي <! عنصر ... إعلانات وقد جربت الحل المقترح في المنتدى وأشار إلى Tomalak ، لكنه لا يعمل ، لقد استخدمت Java 1.6 في بيئة Linux. أعتقد أنه إذا لم يعد المقترح ، فسوف أقوم ببضع طرق لتجاهل العقد النصية البيضاء

هل كانت مفيدة؟

المحلول

"تجاهل العدوى" لا يدور حول الإزالة الكل العقد النصية النقية ، فقط العقد البيضاء التي يتم وصف والديها في المخطط بأنها ذات محتوى العناصر-أي أنها تحتوي فقط على عناصر أخرى ولا توجد نص.

إذا لم يكن لديك مخطط (DTD أو XSD) قيد الاستخدام ، فإن المحتوى العامل الافتراضي للمختلط ، لذلك لن يكون لهذه المعلمة أي تأثير أبدًا. (ما لم يوفر المحلل المحلل امتدادًا غير قياسي DOM لعلاج جميع العناصر غير المعروفة على أنها محتوى العناصر ، والتي بقدر ما أعرف أنها متوفرة لجافا لا.)

يمكنك اختراق المستند في الطريق إلى المحلل لتضمين معلومات المخطط ، على سبيل المثال عن طريق إضافة مجموعة فرعية داخلية إلى <! doctype ... [...] استخدم المعلمة DethursingElementContentWhiteSpace.

أو ، ربما من الأسهل ، يمكنك فقط تجريد العقد البيضاء ، إما في عملية ما بعد العملية ، أو عند استخدامها باستخدام LSParserFilter.

نصائح أخرى

This is a (really) late answer, but here is how I solved it. I wrote my own implementation of a NodeList class. It simply ignores text nodes that are empty. Code follows:

private static class NdLst implements NodeList, Iterable<Node> {

    private List<Node> nodes;

    public NdLst(NodeList list) {
        nodes = new ArrayList<Node>();
        for (int i = 0; i < list.getLength(); i++) {
            if (!isWhitespaceNode(list.item(i))) {
                nodes.add(list.item(i));
            }
        }
    }

    @Override
    public Node item(int index) {
        return nodes.get(index);
    }

    @Override
    public int getLength() {
        return nodes.size();
    }

    private static boolean isWhitespaceNode(Node n) {
        if (n.getNodeType() == Node.TEXT_NODE) {
            String val = n.getNodeValue();
            return val.trim().length() == 0;
        } else {
            return false;
        }
    }

    @Override
    public Iterator<Node> iterator() {
        return nodes.iterator();
    }
}

You then wrap all of your NodeLists in this class and it will effectively ignore all whitespace nodes. (Which I define as Text Nodes with 0-length trimmed text.)

It also has the added benefit of being able to be used in a for-each loop.

I made it works by doing this

DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        dbFactory.setIgnoringElementContentWhitespace(true);
        dbFactory.setSchema(schema);
        dbFactory.setNamespaceAware(true);
NodeList nodeList = element.getElementsByTagNameNS("*", "associate");

I ended up following @bobince's idea of using an LSParserFilter. Yes, the interface is documented at https://docs.oracle.com/javase/7/docs/api/org/w3c/dom/ls/LSParserFilter.html but it's very hard to find good example/explanation material. After considerable searching I located DOM Level 3 Load and Save XML Reference Guide at http://www.informit.com/articles/article.aspx?p=31297&seqNum=29 (Nicholas Chase, Mar 14, 2003). That helped me considerably. Here are portions of my code, which does an XML diff with org.custommonkey.xmlunit. (This is a tool written on my own time to help me with paid work, so I have left a lot of things, like better exception handling, for when things are slow.)

I especially like the use of an LSParserFilter because, for my purpose, I will likely add an option in the future to ignore id attributes too, which should be an easy enhancement with this framework.

// A small portion of my main class.
// Other imports may be necessary...
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSParser;
import org.w3c.dom.ls.LSParserFilter;

Document controlDoc = null;
Document testDoc = null;
try {
    System.setProperty(DOMImplementationRegistry.PROPERTY, "org.apache.xerces.dom.DOMImplementationSourceImpl");
    DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
    DOMImplementationLS impl = (DOMImplementationLS) registry.getDOMImplementation("LS");
    LSParser builder = impl.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, null);
    LSParserFilter filter = new InputFilter();
    builder.setFilter(filter);
    controlDoc = builder.parseURI(files[0].getPath());
    testDoc = builder.parseURI(files[1].getPath());
} catch (Exception exc) {
    System.out.println(exc.getMessage());
}

//--------------------------------------

import org.w3c.dom.ls.LSParserFilter;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.traversal.NodeFilter;

public class InputFilter implements LSParserFilter {

    public short acceptNode(Node node) {
        if (Utils.isNewline(node)) {
            return NodeFilter.FILTER_REJECT;
        }
        return NodeFilter.FILTER_ACCEPT;
    }

    public int getWhatToShow() {
        return NodeFilter.SHOW_ALL;
    }

    public short startElement(Element elem) {
        return LSParserFilter.FILTER_ACCEPT;
    }

}

//-------------------------------------
// From my Utils.java:

    public static boolean isNewline(Node node) {
        return (node.getNodeType() == Node.TEXT_NODE) && node.getTextContent().equals("\n");
    }

Try this:

private static Document prepareXML(String param) throws ParserConfigurationException, SAXException, IOException {

        param = param.replaceAll(">\\s+<", "><").trim();
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setIgnoringElementContentWhitespace(true);
        DocumentBuilder builder = factory.newDocumentBuilder();
        InputSource in = new InputSource(new StringReader(param));
        return builder.parse(in);

    }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top