1

我遇到过堆栈溢出问题,但似乎没有一个解决方案可以为我解决问题。

我正在从 Yahoo 检索 XML 数据,它返回如下(为简洁起见被截断)。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<fantasy_content xmlns="http://fantasysports.yahooapis.com/fantasy/v2/base.rng" xmlns:yahoo="http://www.yahooapis.com/v1/base.rng" copyright="Data provided by Yahoo! and STATS, LLC" refresh_rate="31" time="55.814027786255ms" xml:lang="en-US" yahoo:uri="http://fantasysports.yahooapis.com/fantasy/v2/league/328.l.108462/settings">
    <league>
        <league_key>328.l.108462</league_key>
        <league_id>108462</league_id>
        <draft_status>postdraft</draft_status>
    </league>
</fantasy_content>

我在让 XPath 检索任何元素时遇到问题,所以我编写了一个单元测试来尝试解决它,它看起来像:

    final File file = new File("league-settings.xml");
    javax.xml.parsers.DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
    dbFactory.setNamespaceAware(true);
    javax.xml.parsers.DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
    org.w3c.dom.Document doc = dBuilder.parse(file);
    javax.xml.xpath.XPath xPath = XPathFactory.newInstance().newXPath();
    xPath.setNamespaceContext(new YahooNamespaceContext());
    final String expression = "yfs:league";
    final XPathExpression expr = xPath.compile(expression);
    Object nodes = expr.evaluate(doc, XPathConstants.NODESET);

    assert(nodes instanceof NodeList);
    NodeList leagueNodes = (NodeList)nodes;
    int leaguesLength = leagueNodes.getLength();
    assertEquals(leaguesLength, 1);

我为映射命名空间而创建的 YahooNamespaceContext 类如下所示:

public class YahooNamespaceContext implements NamespaceContext {
    public static final String YAHOO_NS = "http://www.yahooapis.com/v1/base.rng";
    public static final String DEFAULT_NS = "http://fantasysports.yahooapis.com/fantasy/v2/base.rng";
    public static final String YAHOO_PREFIX = "yahoo";
    public static final String DEFAULT_PREFIX = "yfs";

    private final Map<String, String> namespaceMap = new HashMap<String, String>();
    public YahooNamespaceContext() {
        namespaceMap.put(DEFAULT_PREFIX, DEFAULT_NS);
        namespaceMap.put(YAHOO_PREFIX, YAHOO_NS);
    }

    public String getNamespaceURI(String prefix) {
        return namespaceMap.get(prefix);
    }

    public String getPrefix(String uri) {
        throw new UnsupportedOperationException();
    }

    public Iterator<String> getPrefixes(String uri) {
        throw new UnsupportedOperationException();
    }

}

任何对具有更多 XML 命名空间经验的人或 Xpath 编译/评估的调试技巧的帮助将不胜感激。

4

2 回答 2

2

如果问题是结果节点列表的长度为零,您是否尝试过更改

final String expression = "yfs:league";

final String expression = "//yfs:league";

?

用于评估 XPath 表达式的上下文似乎doc是文档的根节点。dBuilder.parse(file)返回文档根节点,而不是最外层元素(又名文档元素)。请记住,在 XPath 中,根节点不是元素。所以doc 不是yfs:fantasy_content元素节点,而是它的(不可见的)父节点。

在这种情况下,XPath 表达式"yfs:league"将只选择作为该根节点的直接子节点的元素,其中没有 yfs:league--only yfs:fantasy_content

于 2014-09-16T20:13:42.330 回答
1

XPath 表达式yfs:league等效于child::yfs:league. doc这意味着:找到具有指定本地名称(league)和命名空间URI( )的直接子节点(不是后代http://fantasysports.yahooapis.com/fantasy/v2/base.rng)。

您必须考虑最外层元素 ( fantasy_content) 或搜索后代而不是子节点。

更换

final String expression = "yfs:league";

final String expression = "yfs:fantasy_content/yfs:league";

或与

final String expression = "//yfs:league";

将解决问题。

于 2014-09-16T20:15:25.353 回答