2012-09-05 36 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); 
    } 
}