Java: XML解析器

4
我有一个类似于以下内容的响应XML -
<Response> <aa> <Fromhere> <a1>Content</a1> <a2>Content</a2> </Fromhere> </aa> </Response>

我想从字符串中提取<Fromhere></Fromhere>标签之间的所有内容。请问是否可以通过任何字符串功能或XML解析器来实现?
请给出建议。
5个回答

6

您可以尝试使用XPath方法来简化XML解析:

InputStream response = new ByteArrayInputStream("<Response> <aa> "
        + "<Fromhere> <a1>Content</a1> <a2>Content</a2> </Fromhere> "
        + "</aa> </Response>".getBytes()); /* Or whatever. */

DocumentBuilder builder = DocumentBuilderFactory
        .newInstance().newDocumentBuilder();
Document doc = builder.parse(response);

XPath xpath = XPathFactory.newInstance().newXPath();
XPathExpression expr = xpath.compile("string(/Response/aa/FromHere)");
String result = (String)expr.evaluate(doc, XPathConstants.STRING);

请注意,我没有尝试过这段代码。它可能需要微调。

这不会剥离元素吗? - McDowell
此外,将StringReader包装在StreamSource中会更加不受编码限制。 - McDowell
我该如何读取标签的值呢?例如,我想知道"a1"具有"Content",而"a2"具有"Content"。我的意思是我也想获取"a1"和"a2"。 - Panadol Chong

2
你可以应用一个XSLT样式表来提取所需内容。
这个样式表适合你的例子:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/Response/aa/Fromhere/*">
        <xsl:copy>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

使用以下类似的方式应用它(不包括异常处理):

String xml = "<Response> <aa> <Fromhere> <a1>Content</a1> <a2>Content</a2> </Fromhere> </aa> </Response>";
Source xsl = new StreamSource(new FileReader("/path/to/file.xsl");

TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer(xsl);
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");

StringWriter out = new StringWriter();
transformer.transform(new StreamSource(new StringReader(xml)), new StreamResult(out));

System.out.println(out.toString());

这应该适用于从1.4版本开始的任何Java版本。


你可能想在转换器上设置OutputKeys.OMIT_XML_DECLARATION="yes"。 - McDowell
实际上我在XSL中使用了HTML方法来抑制XML声明,但是您的建议更好。我已经将其包含在响应中,谢谢。 - Massimiliano Fliri

2

通过XML解析器。使用字符串函数解析XML是一个不好的想法...
除了上面提到的Sun教程外,您还可以查看Java和XML的DZone Refcardz,我发现这是一个很好的简洁解释如何做到这一点。
但是,很可能有很多关于此主题的Web资源,包括在本网站上。


2
指出使用“字符串函数解析XML”是一个不好的想法。 - Nick Holt
DZone Refcardz 看起来很有趣。但说真的:为了注册一个“免费”的服务,需要完整地址和电话号码? - Joachim Sauer

0

这应该可以工作

import java.util.regex.*

Pattern p = Pattern.compile("<Fromhere>.*</Fromhere>");
Matcher m = p.matcher(responseString);
String whatYouWant = m.group();

使用Scanner可能会更冗长一些,但也可以工作。

是否这是一个好主意,还得由比我更有经验的人来判断。


嗨,这个注释不完整。在“work:”后面看不到任何内容。 - Pavan
我强烈不建议使用字符串函数(或正则表达式)处理XML。这样做只有在XML具有与您示例完全相同的结构并且任何较小的更改都会破坏它时才能起作用(例如添加属性,更改属性顺序,自闭合标记等)。它太容易受损了。请使用真正的XML解析器。 - Joachim Sauer

0
一个选择是使用StreamFilter
class MyFilter implements StreamFilter {
  private boolean on;

  @Override
  public boolean accept(XMLStreamReader reader) {
    final String element = "Fromhere";
    if (reader.isStartElement() && element.equals(reader.getLocalName())) {
      on = true;
    } else if (reader.isEndElement()
        && element.equals(reader.getLocalName())) {
      on = false;
      return true;
    }
    return on;
  }
}

结合Transformer,您可以使用它来安全地解析逻辑等效的标记,例如:

<Response>
  <!-- <Fromhere></Fromhere> -->
  <aa>
    <Fromhere>
      <a1>Content</a1> <a2>Content</a2>
    </Fromhere>
  </aa>
</Response>

演示:

StringWriter writer = new StringWriter();

XMLInputFactory inputFactory = XMLInputFactory.newInstance();
XMLStreamReader reader = inputFactory
    .createXMLStreamReader(new StringReader(xmlString));
reader = inputFactory.createFilteredReader(reader, new MyFilter());
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.transform(new StAXSource(reader), new StreamResult(writer));

System.out.println(writer.toString());

这是对Massimiliano Fliri方法的编程变体。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接