2012-09-05 60 views
1

我被困在開發一個解析大量XML的特定XML解析器。解析嵌套在其他XML值中的XML標記

我的問題是我很困惑如何解析嵌套在其他XML值的XML標籤。 我的輸入文件看起來像這樣。

<main> 
<step> 
    <para>Calculate the values from the pool</para> 
</step> 
<step> 
     <para>Use these(<internalRef id ="003" xlink:actuate="onRequest" xlink:show="replace" xlink:href="max003"/>) values finally</para> 
</step> 
</main> 

我能夠使用xpath獲取第一個步驟標記的值。 我的問題是如何使用xpath獲取第二步值,或者更確切地說,如何識別何時在值標籤內啓動新標籤。

對於例如,我的第二個步驟XPath是返回我這樣的結果 - 使用這些()值最後

這裏作爲我的目標是GET-使用這些(max003)值終於

max003值已經從的xlink採取:HREF

加法 - 我可以通過編寫單獨的xpath來獲取id的各個值,啓動和顯示。我的問題是我需要得到的XLink後後這些值之前東西,括號內的max003值:HREF值是max003,並將其發送跨線進行顯示。 所以我正在尋找一種方法來確定哪裏和何時子節點ID已經開始?一種機制將它塞入圓括號內。

+0

或者這是無效XML的情況嗎? – Napster

+0

我想你可能會發現解析是看到內部標籤作爲''節點的子節點...即'' - >'' – MadProgrammer

+1

沒有xml值中嵌套的xml標籤這樣的事情。 –

回答

2

這個XPath表達式的評價:

concat(/*/step[2]/para/text()[1], 
     /*/step[2]/para/internalRef/@xlink:href, 
     /*/step[2]/para/text()[2]) 

上提供的XML文檔(糾正爲命名空間格式化):

<main xmlns:xlink="Undefined namespace"> 
    <step> 
     <para>Calculate the values from the pool</para> 
    </step> 
    <step> 
     <para>Use these(<internalRef id ="003" xlink:actuate="onRequest" xlink:show="replace" xlink:href="max003"/>) values finally</para> 
    </step> 
</main> 

產生通緝的結果

Use these(max003) values finally 

請注意:您需要使用您的XPath API「註冊XLink命名空間」,爲了讓這個XPath表達式沒有一個錯誤進行評估。

基於XSLT的驗證

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:xlink="Undefined namespace"> 
<xsl:output method="text"/> 
<xsl:strip-space elements="*"/> 

<xsl:template match="/"> 
    <xsl:copy-of select= 
    "concat(/*/step[2]/para/text()[1], 
      /*/step[2]/para/internalRef/@xlink:href, 
      /*/step[2]/para/text()[2]) 
    "/> 
</xsl:template> 
</xsl:stylesheet> 

當這個變換所提供的XML文檔(上文),XPath表達式求值和該評價的結果施加被複制到輸出

Use these(max003) values finally 
+0

如果他的元素可能包含多個元素和它們之間的文本?這可以用通用的方式用XPath表達式解決嗎? – predi

+1

@predi,是的,XPath 2.0。是的,如果預先知道'para'的所有孩子的數量和確切類型,則使用XPath 1.0。不,使用XPath 1.0,如果'para'的所有孩子的數量和確切類型未提前知道 –

1

儘可能靠近我可以告訴大家,我認爲你的分析器是看你構建一個有點像

step 
+- para 
    +-id 

它然後包裹在「文本」的內容一起提取ID節點...

(這純屬猜測)

UPDATE

如果我走純粹節點T稀土元素(列出每個孩子)這就是我得到

main 
    step 
    para 
     #text - Calculate the values from the pool 
    step 
    para 
     #text - Use these(
     id 
     #text -) values finally 

這意味着,「ID」,是「對」

2

的孩子你不能單獨使用XPath的事情。你有什麼混合內容XML,這意味着一個元素可能包含文本值和子元素。您只能使用XPath一次引用其中的一個,並且您也不能只從多個XPath表達式中獲取您的內容,因爲文本值可能會包含子元素,如您在示例中所述。

我建議你使用XSLT來轉換文檔,然後像現在這樣使用XPath查詢轉換後的文檔。另一種方法是編寫你自己的解析器,它能夠正確處理你的嵌套元素。

這XSLT可能會爲你工作(還沒有徹底測試):

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xlink="http://www.w3.org/1999/xlink"> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="@* | node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@* | node()"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="internalRef"> 
     <xsl:value-of select="@xlink:href"/> 
    </xsl:template> 
</xsl:stylesheet> 

當然,你需要以改造原始文檔使用XSLT處理器。

而且解析器看起來是這樣的(注意,這是一個StAX的解析器只是骨架代碼):

import java.io.StringReader; 
import java.util.Iterator; 
import javax.xml.stream.XMLEventReader; 
import javax.xml.stream.XMLInputFactory; 
import javax.xml.stream.XMLStreamException; 
import javax.xml.stream.XMLStreamReader; 
import javax.xml.stream.events.Attribute; 
import javax.xml.stream.events.Characters; 
import javax.xml.stream.events.EndElement; 
import javax.xml.stream.events.StartElement; 
import javax.xml.stream.events.XMLEvent; 

public class ExampleStAXParser { 

    private static final int STATE_UNDEFINED = 1; 
    private static final int STATE_MAIN = 2; 
    private static final int STATE_STEP = 3; 
    private static final int STATE_PARA = 4; 

    private static final String EL_MAIN = "main"; 
    private static final String EL_STEP = "step"; 
    private static final String EL_PARA = "para"; 
    private static final String EL_INTERNAL_REF = "internalRef"; 
    private static final String ATT_HREF = "href"; 

    private int state = STATE_UNDEFINED; 
    private String characters; 

    public void parse(String xmlString) throws XMLStreamException, Exception { 


     XMLEventReader reader = null; 
     try { 
      if (xmlString == null || xmlString.isEmpty()) { 
       throw new IllegalArgumentException("Illegal initializiation (xmlString is null or empty)"); 
      } 
      StringReader stringReader = new StringReader(xmlString); 
      XMLInputFactory inputFact = XMLInputFactory.newInstance(); 
      XMLStreamReader streamReader = inputFact.createXMLStreamReader(stringReader); 
      reader = inputFact.createXMLEventReader(streamReader); 

      while (reader.hasNext()) { 
       XMLEvent event = reader.nextEvent(); 

       if (event.isCharacters()) { 
        characters(event); 
       } 
       if (event.isStartElement()) { 
        startElement(event); 
        // handle attributes 
        Iterator<Attribute> attributes = event.asStartElement().getAttributes(); 
        while(attributes.hasNext()) { 
         attribute(attributes.next()); 
        } 
       } 
       if (event.isEndElement()) { 
        endElement(event); 
       } 
       if (event.isStartDocument()) { 
        startDocument(event); 
       } 
       if (event.isEndDocument()) { 
        endDocument(event); 
       } 

      }    
     } catch (XMLStreamException ex) { 
      throw ex; 
     } finally { 
      try { 
       if (reader != null) { 
        reader.close(); 
       } 
      } catch (XMLStreamException ex) { 
      } 
     } 
    } 

    private void attribute(XMLEvent event) throws Exception { 
     if (state == STATE_PARA) { 
      Attribute attr = (Attribute) event; 
      String name = attr.getName().getLocalPart(); 
      if (ATT_HREF.equals(name)) { 
       if (characters == null) { 
        characters = attr.getValue(); 
       } else { 
        characters += attr.getValue(); 
       } 
      } 
     } else 
      throw new Exception("unexpected attribute"); 
    } 

    private void characters(XMLEvent event) throws Exception { 
     Characters asCharacters = event.asCharacters(); 
     if (asCharacters.isWhiteSpace()) 
      return; 
     if (state == STATE_PARA) {    
      if (characters == null) { 
       characters = asCharacters.getData(); 
      } else { 
       characters += asCharacters.getData(); 
      } 
     } else 
      throw new Exception("unexpected attribute"); 
    } 

    private void startElement(XMLEvent event) throws Exception { 
     StartElement startElement = event.asStartElement(); 
     String name = startElement.getName().getLocalPart(); 
     switch (state) { 
      case STATE_UNDEFINED: 
       if (name.equals(EL_MAIN)) { 
        state = STATE_MAIN; 
        System.out.println("Element: " + name); 
       } else 
        throw new Exception("unexpected element"); 
       break; 
      case STATE_MAIN: 
       if (name.equals(EL_STEP)) { 
        state = STATE_STEP; 
        System.out.println("Element: " + name); 
       } else 
        throw new Exception("unexpected element"); 
       break; 
      case STATE_STEP: 
       if (name.equals(EL_PARA)) { 
        state = STATE_PARA; 
        System.out.println("Element: " + name); 
       } else 
        throw new Exception("unexpected element"); 
       break; 
      case STATE_PARA: 
       if (name.equals(EL_INTERNAL_REF)) { 
        System.out.println("Element: " + name); 
       } else 
        throw new Exception("unexpected element"); 
       break; 
      default: 
       throw new Exception("unexpected element"); 
     } 
    } 

    private void endElement(XMLEvent event) throws Exception { 
     EndElement endElement = event.asEndElement(); 
     String name = endElement.getName().getLocalPart(); 
     switch (state) { 
      case STATE_MAIN: 
       if (name.equals(EL_MAIN)) { 
        state = STATE_UNDEFINED; 
       } else 
        throw new Exception("unexpected element"); 
       break; 
      case STATE_STEP: 
       if (name.equals(EL_STEP)) { 
        state = STATE_MAIN; 
       } else 
        throw new Exception("unexpected element"); 
       break; 
      case STATE_PARA: 
       if (name.equals(EL_INTERNAL_REF)) { 
        // do nothing 
       } else if (name.equals(EL_PARA)) { 
        System.out.println("Value: " + String.valueOf(characters)); 
        characters = null; 
        state = STATE_STEP; 
       } else 
        throw new Exception("unexpected element"); 
       break; 
      default: 
       throw new Exception("unexpected element"); 
     } 
    } 

    private void startDocument(XMLEvent event) { 
     System.out.println("Parsing started"); 
    } 

    private void endDocument(XMLEvent event) { 
     System.out.println("Parsing ended"); 
    } 

    public static void main(String[] argv) throws XMLStreamException, Exception { 
     String xml = ""; 
     xml += "<main>"; 
     xml += "<step>"; 
     xml += " <para>Calculate the values from the pool</para>"; 
     xml += "</step>"; 
     xml += "<step>"; 
     xml += "  <para>Use these(<internalRef id =\"003\" actuate=\"onRequest\" show=\"replace\" href=\"max003\"/>) values finally</para>"; 
     xml += "</step>"; 
     xml += "</main>"; 

     ExampleStAXParser parser = new ExampleStAXParser(); 
     parser.parse(xml); 
    } 
}