【问题标题】:Java Reading XML - Stops at '<' special characterJava 读取 XML - 在“<”特殊字符处停止
【发布时间】:2012-08-06 09:20:14
【问题描述】:

我正在制作一个练习应用程序,目的是从 RSS 提要中读取数据。

到目前为止一切顺利,只是我的应用程序遇到了特殊字符问题。它读取节点内的第一个特殊字符,然后移动到下一个节点。

任何帮助都将不胜感激,对于后面的大代码块,我们深表歉意。

RSS 提要 - www.usu.co.nz/usu-news/rss.xml

<title>Unitec hosts American film students</title>
<link>http://www.usu.co.nz/node/4640</link>
<description>&lt;p&gt;If you’ve been hearing American accents around the Mt Albert campus over the past week.</description>

显示代码

String xml = XMLFunctions.getXML();
Document doc = XMLFunctions.XMLfromString(xml);

NodeList nodes = doc.getElementsByTagName("item");

for (int i = 0; i < nodes.getLength(); i++) 
{                           
    Element e = (Element)nodes.item(i);
    Log.v("XMLTest", XMLFunctions.getValue(e, "title"));
    Log.v("XMLTest", XMLFunctions.getValue(e, "link"));
    Log.v("XMLTest", XMLFunctions.getValue(e, "description"));  
    Log.v("XMLTest", XMLFunctions.getValue(e, "pubDate"));
    Log.v("XMLTest", XMLFunctions.getValue(e, "dc:creator"));
}

阅读器代码

public class XMLFunctions 
{

public final static Document XMLfromString(String xml)
{

    Document doc = null;

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    try {

        DocumentBuilder db = dbf.newDocumentBuilder();

        InputSource is = new InputSource();
        is.setCharacterStream(new StringReader(xml));
        doc = db.parse(is); 

    } catch (ParserConfigurationException e) {
        System.out.println("XML parse error: " + e.getMessage());
        return null;
    } catch (SAXException e) {
        System.out.println("Wrong XML file structure: " + e.getMessage());
        return null;
    } catch (IOException e) {
        System.out.println("I/O exeption: " + e.getMessage());
        return null;
    }

    return doc;

}

/** Returns element value
  * @param elem element (it is XML tag)
  * @return Element value otherwise empty String
  */
 public final static String getElementValue( Node elem ) {
     Node kid;
     if(elem != null)
     {
         if (elem.hasChildNodes())
         {
             for(kid = elem.getFirstChild(); kid != null; kid = kid.getNextSibling())
             {
                 if( kid.getNodeType() == Node.TEXT_NODE  )
                 {
                     return kid.getNodeValue();
                 }
             }
         }
     }
     return "";
 }

 public static String getXML(){  
        String line = null;

        try {

            DefaultHttpClient httpClient = new DefaultHttpClient();
            HttpPost httpPost = new HttpPost("http://www.usu.co.nz/usu-news/rss.xml");

            HttpResponse httpResponse = httpClient.execute(httpPost);
            HttpEntity httpEntity = httpResponse.getEntity();
            line = EntityUtils.toString(httpEntity);

        } catch (UnsupportedEncodingException e) {
            line = "<results status=\"error\"><msg>Can't connect to server</msg></results>";
        } catch (MalformedURLException e) {
            line = "<results status=\"error\"><msg>Can't connect to server</msg></results>";
        } catch (IOException e) {
            line = "<results status=\"error\"><msg>Can't connect to server</msg></results>";
        }

        return line;

}

public static int numResults(Document doc){     
    Node results = doc.getDocumentElement();
    int res = -1;

    try{
        res = Integer.valueOf(results.getAttributes().getNamedItem("count").getNodeValue());
    }catch(Exception e ){
        res = -1;
    }

    return res;
}

public static String getValue(Element item, String str) {       
    NodeList n = item.getElementsByTagName(str);        
    return XMLFunctions.getElementValue(n.item(0));
}
}

输出

Unitec hosts American film students
http://www.usu.co.nz/node/4640
<
Wed, 01 Aug 2012 05:43:22 +0000
Phillipa

【问题讨论】:

  • 不是一个答案,但您是否考虑过使用更高级别的 XML API 来读取这些项目?诸如 Apache XMLBeans 之类的库使得将 XML 解析为方便的 Java 对象变得非常容易。当涉及到“有趣”的角色和其他奇怪的东西时,它们也经过了很好的测试。

标签: java xml rss special-characters


【解决方案1】:

您的代码仅从元素中提取 first 子文本节点。 DOM 规范允许多个相邻的文本节点,所以我怀疑这里发生的事情是您的解析器表示&lt;p&gt;,其余文本(至少)作为四个单独的文本节点。您要么需要将节点连接成一个字符串,要么在包含元素节点上调用 normalize()(这会修改 DOM 树以将相邻的文本节点合并为一个)。

有各种库可以帮助您。例如,如果您的应用程序使用 Spring 框架,那么 org.springframework.util.xml.DomUtils 有一个 getTextValue 静态方法,可以从元素中提取完整的文本值。

【讨论】:

  • +1:对于这个问题,这些可能是比我发布的更好的解决方案。
【解决方案2】:

你的功能

public final static String getElementValue( Node elem ) {
    Node kid;
    if(elem != null)
    {
        if (elem.hasChildNodes())
        {
            for(kid = elem.getFirstChild(); kid != null; kid = kid.getNextSibling())
            {
                if( kid.getNodeType() == Node.TEXT_NODE  )
                {
                    return kid.getNodeValue();
                }
            }
        }
    }
    return "";
}

正在返回给定元素下的第一个文本节点。单个标签中的一段文本可以拆分为多个文本节点,而这往往发生在存在特殊字符的情况下。

您可能应该将所有文本节点附加到返回值的字符串中。

类似这样的东西可能会起作用:

public final static String getElementValue( Node elem ) {
    if ((elem == null) || (!(elem.hasChildNodes())))
        return "";

    Node kid;
    StringBuilder builder = new StringBuilder();
    for(kid = elem.getFirstChild(); kid != null; kid = kid.getNextSibling())
    {
        if( kid.getNodeType() == Node.TEXT_NODE  )
        {
            builder.append(kid.getNodeValue());
        }
    }
    return builder.toString();
}

【讨论】:

  • 可以使用StringBuilder时请不要使用StringBuffer。
【解决方案3】:

有点离题,但您可能想查看现有的 RSS 框架之一,例如 ROME。比重新发明轮子要好。

【讨论】:

    【解决方案4】:

    &lt;?xml version="1.0" encoding="UTF-8"?&gt; 似乎不见了。也没有根元素。

    【讨论】:

    • 我假设我们在这里看到了 XML 的片段。请注意,它不包含贡献者“Phillipa”,但在输出中引用了它。
    • 是的,抱歉,应该澄清一下。我只是试图显示 XML 的一小部分,以便您可以看到它有问题的特殊字符。
    【解决方案5】:

    您确定 XML 字符串没有被 DefaultHttpClient 转换吗? 我尝试了您的代码并更改了 XMLFunctions.getXML() 方法以直接提供 XML 字符串,而不是通过 DefaultHttpClient 获取它,输出类似于

    Unitec hosts American film students
    http://www.usu.co.nz/node/4640
    <p>If you’ve been hearing American accents around the Mt Albert campus over the past week.
    

    正如预期的那样。

    【讨论】:

      猜你喜欢
      • 2016-07-16
      • 1970-01-01
      • 1970-01-01
      • 2014-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-08
      相关资源
      最近更新 更多