这个 SAX 解析和 Xpath 代码有什么问题?

what is wrong with this SAX parsing and Xpath code?

通读 Maven By Example,这是几年前的一本书,但我假设是从存储库中检索正确的版本,我只是想知道第一个单元测试出了什么问题例如。

我们有一个 xml 文件,文件开头:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<rss version="2.0" xmlns:yweather="http://xml.weather.yahoo.com/ns/rss/1.0" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">
 <channel>
 <title>Yahoo! Weather - New York, NY</title>
 <link>http://us.rd.yahoo.com/dailynews/rss/weather/New_York__NY/*http://weather.yahoo.com/forecast/10002_f.html</link>
 <description>Yahoo! Weather for New York, NY</description>
 <language>en-us</language>
 <lastBuildDate>Sat, 10 Nov 2007 8:51 pm EDT</lastBuildDate>
 <ttl>60</ttl>

 <!--************ THIS IS THE LINE WE'RE INTERESTED IN ************ -->
 <yweather:location city="New York" region="NY" country="US" />

 <yweather:units temperature="F" distance="mi" pressure="in" speed="mph" />

并且这个 xml 文件正在通过 InputStream 读入并解析:

    Weather weather = new Weather();
    log.info("Creating XML Reader");
    SAXReader xmlReader = createXmlReader();
    Document doc = xmlReader.read(inputStream);

    // this proves we're getting the text OK
    // String xml_text_content = doc.getStringValue();
    // log.info( "=== xml text content: |" + xml_text_content + "|" );

    log.info("Parsing XML Response");
    weather.setCity(doc.valueOf("/rss/channel/y:location/@city"));
    String city_str = doc.valueOf("/rss/channel/y:location/@city");
    // this should say "New York"... but I'm getting an empty string
    log.info( "=== doc value of for city: |" + city_str + "|" );

...我对RSS和XPath知之甚少,抱歉。好像有知识的人可能会看到问题!

PS 我尝试在 xml 文件中将 "yweather:location" 更改为 "y:location",然后在代码中将 "y:location" 更改为 "yweather:location"。 .. 都抛出异常。后一种情况:

528 INFO YahooParser - Parsing XML Response Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.096 sec <<< FAILURE! testParser(org.sonatype.mavenbook.custom.weather.yahoo.YahooParserTest) Time el apsed: 0.094 sec <<< ERROR!
org.dom4j.XPathException: Exception occurred evaluting XPath: /rss/channel/yweather:location/@city. Exception: XPath expression uses unbound namespace prefix yweather
at org.dom4j.xpath.DefaultXPath.handleJaxenException(DefaultXPath.java:374) at org.dom4j.xpath.DefaultXPath.valueOf(DefaultXPath.java:185) at org.dom4j.tree.AbstractNode.valueOf(AbstractNode.java:191) at org.sonatype.mavenbook.custom.weather.YahooParser.parse(YahooParser.j ava:28) at org.sonatype.mavenbook.custom.weather.yahoo.YahooParserTest.testParse r(YahooParserTest.java:36)

"unbound namespace prefix yweather"...???

以下代码适用于我:

import java.io.File;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;

public class TestSax {

    public static void main(String[] args) throws DocumentException {
        SAXReader xmlReader = new SAXReader();
        Document doc = xmlReader.read(new File("D:/Temp/sax.xml"));
        String city_str = doc.valueOf("/rss/channel/yweather:location/@city");
        System.out.println( "=== doc value of for city: |" + city_str + "|" );
    }
}

我使用了 dom4j 并需要来自 here 的 jar jaxen。检查您是否使用相同的库。

另请注意,我将代码 y:location 更改为 yweather:location

只需提供解决方案(对我有用),以防同一本书的任何读者遇到同样的问题。

在第 38 页(在我的版本中)- 第 4.3 节 "Creating the Simple Weather Project",我们被告知 运行 这个命令:

$ mvn archetype:generate -DgroupId=org.sonatype.mavenbook.custom DartifactId=simple-weather -Dversion=1.0

在我的系统上 (Windows 7) 这创建了错误的目录结构:在 "main" 和 "test" 下有一个 "spurious" 目录在 "mavenbook": "custom".

在第 43 页,当您开始创建 "main" 和 "test" 目录结构时,比我聪明的人会明白 "custom" 目录不应该存在...

我的解决方案(我终于找到了)确实是摆脱这个 "custom" 目录,确保路径在 xxxxTest 类 的导入语句中匹配 OK,最后到确保父 pom.xml 与目录 "simple-weather" 在同一目录中(项目 pom.xml 在后一个目录中)。

也可以按照书中的解释下载现成的项目(因为它本来就是,没有 "custom" 目录)...

PS 我觉得这是值得的 - 如果您的 builder/tester 应用程序没有按预期工作,您将何去何从?

PPS 这也是值得的,因为 Maven 确实设计得很好而且功能强大...

回复旧 post 以防有人想知道解决方案(比如我)我同意上面的自定义文件夹问题,但它缺少 XPath 问题的实际解决方案。

本书有

private SAXReader createXmlReader() {
Map<String,String> uris = new HashMap<String,String>();
uris.put( "y", "http://xml.weather.yahoo.com/ns/rss/1.0" );

将散列键更改为 'yweather',将 Xpath 更改为 yweather:location(在代码中,只要 y: 应该是 yweather:....),如上面的评论将起作用

uris.put( "yweather", "http://xml.weather.yahoo.com/ns/rss/1.0" );