2016-03-15 52 views
2

我用dom4j解析一個xml文件,我得到了一個帶有行號的文檔,我想用行號來定位所有帶有行號的節點並操作這些節點。使用dom4j找到節點的行號

有沒有辦法使用dom4j或其他DOM API來實現這個?

+0

定位節點似乎不是一個好主意,你總是應該分析特定節點;想象一下如果有人更改xml文件會發生什麼 – jam

+0

這個想法是我有一個檢查器,可以檢查這個xml文件的錯誤(實際上是一個xmi文件),並返回一個錯誤列表中的行號。所以我可以做一個foreach循環,使用行號來定位和修復特定的節點。 –

+0

你可以使用一個id作爲每個節點的屬性,並返回一個id列表 ,它應該被修復;然後通過ID的 – jam

回答

2

,能夠延長DOM4J爲包括用於元素的行號的最後一個測試節點,但它有點誇張,而不是100%準確(你可以得到開始元素的「>」字符的行號)。

也許,更健壯的方法是報告每個有問題的元素的XPath表達式,然後使用這些表達式來修復它。

然而,只是爲了好玩,這裏是如何將在DOM4J行號信息的完整的例子:通過行號

public class LineNumber { 

    public static void main(String[] args) throws Exception { 

     SAXReader reader = new MySAXReader(); 
     reader.setDocumentFactory(new LocatorAwareDocumentFactory()); 

     Document doc = reader 
       .read(new StringReader("<root foo='bar' > \n<alfa/>\n<beta/>\n<gamma/>\n</root>\n")); 
     doc.accept(new VisitorSupport() { 
      @Override 
      public void visit(Element node) { 
       System.out.printf("%d: %s\n", 
         ((LocationAwareElement) node).getLineNumber(), 
         node.getName()); 
      } 
     }); 

    } 

    static class MySAXReader extends SAXReader { 

     @Override 
     protected SAXContentHandler createContentHandler(XMLReader reader) { 
      return new MySAXContentHandler(getDocumentFactory(), 
        getDispatchHandler()); 
     } 

     @Override 
     public void setDocumentFactory(DocumentFactory documentFactory) { 
      super.setDocumentFactory(documentFactory); 
     } 

    } 

    static class MySAXContentHandler extends SAXContentHandler { 

     private Locator locator; 

     // this is already in SAXContentHandler, but private 
     private DocumentFactory documentFactory; 

     public MySAXContentHandler(DocumentFactory documentFactory, 
       ElementHandler elementHandler) { 
      super(documentFactory, elementHandler); 
      this.documentFactory = documentFactory; 
     } 

     @Override 
     public void setDocumentLocator(Locator documentLocator) { 
      super.setDocumentLocator(documentLocator); 
      this.locator = documentLocator; 
      if (documentFactory instanceof LocatorAwareDocumentFactory) { 
       ((LocatorAwareDocumentFactory)documentFactory).setLocator(documentLocator); 
      } 

     } 

     public Locator getLocator() { 
      return locator; 
     } 
    } 

    static class LocatorAwareDocumentFactory extends DocumentFactory { 

     private Locator locator; 

     public LocatorAwareDocumentFactory() { 
      super(); 
     } 

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

     @Override 
     public Element createElement(QName qname) { 
      LocationAwareElement element = new LocationAwareElement(qname); 
      if (locator != null) 
       element.setLineNumber(locator.getLineNumber()); 
      return element; 
     } 

    } 

    /** 
    * An Element that is aware of it location (line number in) in the source document 
    */ 
    static class LocationAwareElement extends DefaultElement { 

     private int lineNumber = -1; 

     public LocationAwareElement(QName qname) { 
      super(qname); 
     } 

     public LocationAwareElement(QName qname, int attributeCount) { 
      super(qname, attributeCount); 

     } 

     public LocationAwareElement(String name, Namespace namespace) { 
      super(name, namespace); 

     } 

     public LocationAwareElement(String name) { 
      super(name); 

     } 

     public int getLineNumber() { 
      return lineNumber; 
     } 

     public void setLineNumber(int lineNumber) { 
      this.lineNumber = lineNumber; 
     } 

    } 

} 
+0

感謝您的幫助。您顯示的代碼是在每個節點中添加一個行號作爲屬性。我的想法基於你的代碼,就是構建一個map,它將lineNum存儲爲key和node作爲值。這就是我們可以在這張地圖上通過lineNum得到一個節點。 –

+0

只要注意,你可以有每行一個以上的元素,所以在地圖必須配有多值 –

+0

是的,我關心的是,所以我加了LINENUM和colNum爲好,定位節點。這個想法很有用! Merci!所以我現在不能投票。 –

0

您的檢查器可以在您的節點中設置一個屬性,將其標記爲修復。 這將是讀取文件行的​​替代方案。之後只需查找具有此特定屬性的節點並重構它。

<?xml version="1.0" encoding="UTF-8"?> 
<tests> 
    <test>okay</test> 
    <test>good</test> 
    <test>error</test> 
</tests> 

現在解析XML文件和標記以被固定

public void parse(){ 

    SAXReader reader = new SAXReader(); 
    DocumentFactory documentFactory = DocumentFactory.getInstance(); 
    Document document = reader.read("test.xml"); 
    Element root = document.getRootElement(); 

    for (Iterator<Element> iterator = root.elementIterator();iterator.hasNext();){ 
     Element element = iterator.next(); 

     //check for your error and set fix flag, if not already happend 

     if(element.getText().equals("error") && 
      element.attributeValue("todo") == null) { 

      Attribute fix = documentFactory.createAttribute(element, "todo" ,"fix"); 
      element.add(fix); 
     } 
    } 

    // update xml file 

    XMLWriter xmlWriter = new XMLWriter(new FileWriter("test.xml")); 
    xmlWriter.write(document); 
    xmlWriter.close(); 
} 

輸出XML

enter <?xml version="1.0" encoding="UTF-8"?> 
<tests> 
    <test>okay</test> 
    <test>good</test> 
    <test todo="fix">error</test> 
</tests> 
+0

感謝您的回答!這可能是一個想法。雖然這不完全是我的,但它給了我一個提示。 –