1. 程式人生 > >dom4j如何獲取節點的行數,列數

dom4j如何獲取節點的行數,列數

在使用dom4j解析xml檔案時,可能會對一些節點做檢測,判斷是否符合schema,對一些不符合的節點要作出提示。為了使作出的提示更友好,還需要指出錯誤在哪裡。但是dom4j並沒有提供相關的功能,或者說這個功能隱藏的很深。搜尋了一下,發現這個問題的答案很少。我在一個mail(https://www.mail-archive.com/[email protected]/msg02769.html)中得到了提示,摸索了出來,巨麻煩。該mail提到了主要的過程:

org.xml.sax.Locator locator = new …;
DocumentFactory documentFactory = new DocumentFactoryWithLocator(locator);
SAXContentHandler contentHandler = new SAXContentHandler(documentFactory);
contentHandler.setDocumentLocator(locator);
org.xml.sax.XMLReader reader = …;
reader.setContentHandler(contentHandler );
reader.parse(…);
Document document = contentHandler.getDocument();


在DocumentFactory中:

public Element createElement(QName qname) {
	ElementWithLocation element =  new ElementWithLocation (qname);
    element.setLocation(locator.getLineNumber(),
	locator.getColumnNumber());
    return element;
}
方向是對的,但是按照這個方法做出來,卻得不到正確的結果。原因是,SAXReader中的XMLReader在呼叫parse方法時,會重新賦值locator,把我傳進去的locator覆蓋掉了,這樣在DocumentFactory就不是XMLReader中的locator。dom4j使用的XMLReader是org.apache.xerces中的SAXParser,該類繼承了AbstractSAXParser,在AbstractSAXParser中有一個方法:
public void startDocument(XMLLocator locator, String encoding, 
                              NamespaceContext namespaceContext, Augmentations augs)
        throws XNIException {
        
        fNamespaceContext = namespaceContext;

        try {
            // SAX1
            if (fDocumentHandler != null) {
                if (locator != null) {
                    fDocumentHandler.setDocumentLocator(new LocatorProxy(locator));
                }
                fDocumentHandler.startDocument();
            }

            // SAX2
            if (fContentHandler != null) {
                if (locator != null) {
                    fContentHandler.setDocumentLocator(new LocatorProxy(locator));
                }
                fContentHandler.startDocument();
            }
        }
        catch (SAXException e) {
            throw new XNIException(e);
        }

    }

就是這個方法覆蓋了contentHandler的locator。我的做法就是在AbstractSAXParser重新賦值locator的時候獲取這個值,傳遞給DocumentFactory。

上程式碼,首先需要擴充套件原來的Element類,使之可以記錄節點的位置資訊(需要記錄Attribute等的同理)。

public class GokuElement extends DefaultElement {
	private int lineNum = 0, colNum = 0;

	public GokuElement(QName qname) {
		super(qname);
		// TODO Auto-generated constructor stub
	}

	public GokuElement(QName qname, int attrCount) {
		super(qname, attrCount);
	}

	public GokuElement(String name) {
		super(name);
	}

	public GokuElement(String name, Namespace namespace) {
		super(name, namespace);
	}

	public int getColumnNumber() {
		return this.colNum;
	}

	public int getLineNumber() {
		return this.lineNum;
	}

	public void setLocation(int lineNum, int colNum) {
		this.lineNum = lineNum;
		this.colNum = colNum;
	}
}

然後,擴充套件DocumentFactory,讓factory生成我們定義的Element:
public class DocumentFactoryWithLocator extends DocumentFactory {
	private Locator locator;

	public DocumentFactoryWithLocator(Locator locator) {
		super();
		this.locator = locator;
	}

	@Override
	public Element createElement(QName qname) {
		GokuElement element = new GokuElement(qname);
		element.setLocation(this.locator.getLineNumber(), this.locator.getColumnNumber());
		return element;
	}

	@Override
	public Element createElement(String name) {
		GokuElement element = new GokuElement(name);
		element.setLocation(this.locator.getLineNumber(), this.locator.getColumnNumber());
		return element;
	}

	public void setLocator(Locator locator) {
		this.locator = locator;
	}
}

然後擴充套件SAXContentHandler:
public class GokuSAXContentHandler extends SAXContentHandler {
	private DocumentFactoryWithLocator documentFactory = null;

	public GokuSAXContentHandler(DocumentFactory documentFactory2, ElementHandler dispatchHandler) {
		// TODO Auto-generated constructor stub
		super(documentFactory2, dispatchHandler);
	}

	public void setDocFactory(DocumentFactoryWithLocator fac) {
		this.documentFactory = fac;
	}

	@Override
	public void setDocumentLocator(Locator documentLocator) {
		super.setDocumentLocator(documentLocator);
		if (this.documentFactory != null)
			this.documentFactory.setLocator(documentLocator);
	}
}

最後擴充套件SAXReader
public class GokuSAXReader extends SAXReader {
	DocumentFactory docFactory;
	Locator locator;

	public GokuSAXReader(DocumentFactory docFactory) {
		// TODO Auto-generated constructor stub
		super(docFactory);
		this.docFactory = docFactory;
	}

	public GokuSAXReader(DocumentFactory docFactory, Locator locator) {
		// TODO Auto-generated constructor stub
		super(docFactory);
		this.locator = locator;
		this.docFactory = docFactory;
	}

	@Override
	protected SAXContentHandler createContentHandler(XMLReader reader) {
		return new GokuSAXContentHandler(this.getDocumentFactory(), super.getDispatchHandler());
	}

	@Override
	public Document read(InputSource in) throws DocumentException {
		try {
			XMLReader reader = this.getXMLReader();

			reader = this.installXMLFilter(reader);

			EntityResolver thatEntityResolver = super.getEntityResolver();

			if (thatEntityResolver == null) {
				thatEntityResolver = this.createDefaultEntityResolver(in.getSystemId());
				super.setEntityResolver(thatEntityResolver);
			}

			reader.setEntityResolver(thatEntityResolver);

			SAXContentHandler contentHandler = this.createContentHandler(reader);
			contentHandler.setEntityResolver(thatEntityResolver);
			contentHandler.setInputSource(in);

			boolean internal = this.isIncludeInternalDTDDeclarations();
			boolean external = this.isIncludeExternalDTDDeclarations();

			contentHandler.setIncludeInternalDTDDeclarations(internal);
			contentHandler.setIncludeExternalDTDDeclarations(external);
			contentHandler.setMergeAdjacentText(this.isMergeAdjacentText());
			contentHandler.setStripWhitespaceText(this.isStripWhitespaceText());
			contentHandler.setIgnoreComments(this.isIgnoreComments());
			reader.setContentHandler(contentHandler);

			this.configureReader(reader, contentHandler);
			((GokuSAXContentHandler) contentHandler).setDocFactory((DocumentFactoryWithLocator) this.docFactory);
			contentHandler.setDocumentLocator(this.locator);
			reader.parse(in);

			return contentHandler.getDocument();
		} catch (Exception e) {
			if (e instanceof SAXParseException) {
				// e.printStackTrace();
				SAXParseException parseException = (SAXParseException) e;
				String systemId = parseException.getSystemId();

				if (systemId == null) {
					systemId = "";
				}

				String message = "Error on line " + parseException.getLineNumber() + " of document " + systemId + " : "
						+ parseException.getMessage();

				throw new DocumentException(message, e);
			} else {
				throw new DocumentException(e.getMessage(), e);
			}
		}
	}
}
重寫了read(InputSource)方法,使用我們寫的SAXContentHandler。其他簽名的read方法最後都呼叫了這個read方法。

解析檔案的程式碼:

Locator locator = new LocatorImpl();
DocumentFactory docFactory = new DocumentFactoryWithLocator(locator);
SAXReader reader = new GokuSAXReader(docFactory, locator);
Document doc = reader.read(new File("goku.xml"));

需要獲取Element資訊時:

System.out.println(((GokuElement) element).getLineNumber());


相關推薦

dom4j如何獲取節點

在使用dom4j解析xml檔案時,可能會對一些節點做檢測,判斷是否符合schema,對一些不符合的節點要作出提示。為了使作出的提示更友好,還需要指出錯誤在哪裡。但是dom4j並沒有提供相關的功能,或者說這個功能隱藏的很深。搜尋了一下,發現這個問題的答案很少。我在一個mai

Matlab 座標 維

A=eye(3) A(:,1) 結果:    即  尾  座標 表示  列。 A=eye(3) A(1,:) 結果: 即 次尾座標 表示 行。   三維陣列

C#中如何獲取一個二維陣列的兩維長度

int[,] array = new int[,] {{1,2,3},{4,5,6},{7,8,9}};//定義一個3行3列的二維陣列 int row = array.Rank;//獲取行數 int col = array.GetLength(1);//獲取指定維中的元 個

jsp頁面帶有多選框的grid表格如何將勾選中的記錄所有據傳送到後臺。

blank href 後臺 aaa 數據 www hue 選中 cs6 忱分慕兇釉瀑懲防慌虜敝慘緩猩http://jz.docin.com/shuvg316 帳段繁臨市杉聞壞倫捶剎空合戀http://huiyi.docin.com/ogq2843 杏燎乘安轄任凸托飯承臨

Java 獲取二維組的

怎樣 tps lan 個數 元素 mil family 資料 object   對於Object[][] array,array.length返回行數,array[0].length返回列數,元素個數為array.length*array[0].length。   參考

Excel轉Html(十一)--POI處理Excel-獲取sheet總行-總-高-

獲取sheet行總數:sheet.getLastRowNum() 列總數:dataMap.get("maxColNum-" + form.getFormName() 獲取列最多的行,特別注意:sheet.getRow(0).getPhysicalNumberOfCells()不準確 行高:r

實現一個函式列印乘法口訣表口訣表的自己指定 輸入9輸出9*9口訣表輸入12輸出12*12的乘法口訣表。

#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> int main() { int n = 0; printf("請輸入一個數:"); scanf("%d", &n);

C#獲取多維陣列的

效果圖: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.

C#獲取陣列的

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Test02 {     class Program     {        

獲取ResultSet的

獲取ResultSet行數時需要使用可回滾的遊標,自定義方法,獲取行數後要回滾,獲取ResultSet列數時通過ResultSetMetaData類的getColumnCount方法即可獲得。 示例程式碼: publicclass Test ...{    publicsta

轉多不確定

原始需求,有2表如下 SQL> select * from mas; TO TOOLNAME -- ---------- 01 包裹 02 信函 03 掛號信 04 中國速遞 05 EMS 06 DHL 6 rows selected. SQL> select * from putdt; SEN

如何獲取ResultSet的

當我們執行資料庫查詢返回一個ResultSet的時候,很多情況下我們需要知道這個ResultSet的大小,即它的行數和列數。我們知道它的列數可以通過resultSet.getMetaData().getColumnCount()很容易地得到,然而,java API沒有提供直接訪問ResultSet行數的介面

獲取SQL查詢結果集中的

轉自http://cheneyph.iteye.com/blog/477829 在Java中,獲得ResultSet的總行數的方法有以下幾種。 第一種:利用ResultSet的getRow方法來獲得ResultSet的總行數 Statement stmt = con.cre

用C語言中的函式列印乘法口訣表可以任意輸入

#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> void print_table(int line) { int i = 0;

如何將勾選中的記錄所有據傳送到後臺。

w16 user oci dpx ocs cio 數據 mcs cin 8379Kd631S柿http://huiyi.docin.com/fxa140 B12J51素N邢降1http://tushu.docin.com/bkfh0377 V7r佬1乖ZPF17裙htt

How Javascript works (Javascript工作原理) (一) 引擎調用棧

由於 溢出 最好 介紹 error 堆棧溢出 git actual AR 個人總結: 這篇文章對JS底層的工作原理進行了介紹。 原文:https://blog.sessionstack.com/how-does-javascript-actually-work-part

Python獲取Nginx訪問日誌寫入據庫

use arc strip() for create variables *** times war #!/usr/bin/env python # coding: utf-8 # Auther:liangkai # Date:2018/6/26 11:26 # Licen

C#中二維組的

取數 word 二維數組 同學 定義 dimen 行數 nbsp col 最近在項目中用到二維數組,需要獲取數組的行數和列數,本以為是很簡單的一些東西,卻發現網上好多答案都是錯誤的,遂寫下隨筆,希望之後有用到的同學們能夠順利解決答案。 下面是一些關於數組的一些屬性和方法以及