Java和XPath在国会图书馆Web服务上的错误

时间:2013-11-10 06:39:35

标签: java xml xpath

我正在尝试从美国国会图书馆的Web服务中提取书目数据,可以看到结果xml的示例here。总而言之,它看起来像这样:

<zs:searchRetrieveResponse>
  <zs:version>1.1</zs:version>
  <zs:numberOfRecords>1</zs:numberOfRecords>
  <zs:records>
    <zs:record>
      <zs:recordSchema>info:srw/schema/1/mods-v3.2</zs:recordSchema>
      <zs:recordPacking>xml</zs:recordPacking>
      <zs:recordData>
        <mods version="3.2" xsi:schemaLocation="http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-2.xsd">
          (Actual data I care about)
        </mods>
      </zs:recordData>
      <zs:recordPosition>1</zs:recordPosition>
    </zs:record>
  </zs:records>
</zs:searchRetrieveResponse>

我使用xmlbeans编译Java客户端以读取“mods”标记内的数据,因为它具有关联的模式。因此,基本上,我需要提取mods标签及其内容,并将所有内容视为单独的XML文档。我可以用正则表达式做到这一点,但更喜欢真正的XML解决方案(“永远不会用正则表达式解析XML”我不断听到)。我写了以下SSCCE代码。

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
public class LibraryOfCongress {
  public static void main(String[] args) throws XPathExpressionException,
      ParserConfigurationException, SAXException, IOException {
    String URL = "http://z3950.loc.gov:7090/voyager?operation=searchRetrieve&version=1.1&recordSchema=mods&maximumRecords=1&query=bath.isbn=0120502577";
    HttpURLConnection conn = (HttpURLConnection) (new URL(URL))
        .openConnection();
    conn.setRequestMethod("GET");
    int responseCode = conn.getResponseCode();
    String document = null;
    if (responseCode == HttpURLConnection.HTTP_OK) {
      BufferedReader rd;
      InputStream in = conn.getInputStream();
      rd = new BufferedReader(new InputStreamReader(in));
      String tempLine = rd.readLine();
      StringBuilder response = new StringBuilder();
      while (tempLine != null) {
        response.append(tempLine).append("\n");
        tempLine = rd.readLine();
      }
      document = response.toString();
      rd.close();
    }
    if(document==null) return;
    ByteArrayInputStream stream = new ByteArrayInputStream(document.getBytes());
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = factory.newDocumentBuilder();
    Document doc = builder.parse(stream);
    XPathFactory xPathfactory = XPathFactory.newInstance();
    XPath xpath = xPathfactory.newXPath();
    XPathExpression expr = xpath
        .compile("/zs:searchRetrieveResponse/zs:records/zs:recordData");
    Document ret = (Document) expr.evaluate(doc, XPathConstants.NODE);
    if(ret!=null) {
      String retval = ret.toString();
      System.out.println(retval);
    }
  }
}

它没有做任何事情,因为ret为null。我试过的变化:

1)

  .compile("/");
  ...
  String ret = (String) expr.evaluate(doc);

返回没有任何标签的文档。这是我唯一可以输出的输出,但当然我需要将标签传递给xmlbeans生成的客户端。

2)各种其他XPath查询字符串,但我无法获得指定除根节点之外的任何内容的有用输出。

其他一些问题:

1)我已经读过XPathConstants.NODE仍然对原始文档有某种引用,并且不会像我要求的那样生成一个独立的文档。不知道如何处理,我认为拥有独立可解析的节点将是XPath的主要原因之一。

2)我不知道如何处理XPath表达式中的命名空间。我只是猜了一下。

1 个答案:

答案 0 :(得分:1)

如果要对命名空间使用针对XML的XPath,请确保通过调用DocumentBuilder上的http://docs.oracle.com/javase/7/docs/api/javax/xml/parsers/DocumentBuilderFactory.html#setNamespaceAware%28boolean%29来使用名称空间感知DocumentBuilderFactory。然后,要应用带有名称空间的XPath表达式,您需要实现NamespaceContext,我认为Mark已经链接到在他的评论中显示该页面的页面。

至于用XPath选择一个新文档,不,这不是XPath所做的。它允许您选择现有文档中的节点并导航,因此如果您在层次结构中选择特定节点,则获得该节点,但它仍然在文档中包含其所有子节点及其后代以及它的祖先和兄弟节点。

因此,如果您要创建一个新的独立文档,则需要使用DocumentBuilder和http://docs.oracle.com/javase/7/docs/api/javax/xml/parsers/DocumentBuilder.html#newDocument%28%29创建一个,然后您可以importNodeadoptNode使用XPath选择的内容您的输入文档,最后是appendChild