解决XML 中咬住你不放的麻烦

日期: 2008-01-06 作者:William Brogden 来源:TechTarget中国 英文

许多SAXParseException异常报告可以非常容易的理解,但是我们要这篇报告做什么呢? 并且这篇报告是当在解析一个使用文本编辑器创建或编辑的XML文档时将会看到的。目标指令匹配"[xX][mM][lL]"是不被允许的,特别神秘的是在当你知道你不需要试着去创建一个处理指令的时候。   SAXParseException的神秘   许多SAXParseException异常报告可以非常容易的理解,但是我们要这篇报告做什么呢? 并且这篇报告是当在解析一个使用文本编辑器创建或编辑的XML文档时将会看到的。目标指令匹配"[xX][mM][lL]"是不被允许……

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

许多SAXParseException异常报告可以非常容易的理解,但是我们要这篇报告做什么呢? 并且这篇报告是当在解析一个使用文本编辑器创建或编辑的XML文档时将会看到的。目标指令匹配"[xX][mM][lL]"是不被允许的,特别神秘的是在当你知道你不需要试着去创建一个处理指令的时候。

  SAXParseException的神秘

  许多SAXParseException异常报告可以非常容易的理解,但是我们要这篇报告做什么呢? 并且这篇报告是当在解析一个使用文本编辑器创建或编辑的XML文档时将会看到的。
目标指令匹配"[xX][mM][lL]"是不被允许的,特别神秘的是在当你知道你不需要试着去创建一个处理指令的时候。它使得你所得到的就是这些,如果XML声明的开始的"<"字符——

<?xml version="1.0" encoding="UTF-8"?>

  ——并不是这个文件中的第一个字符。这看其他特别的神秘,因为这个文件在打印和查看的时候看起来是很好的。

  在消失代码的情况下

  为了能清楚的说明这个问题,假设你有一个用来保持一个在线签约雇佣的用户的列表XML文档,并用这个作为通常的一个入口。

  < user unum="101">
  < firstname>Bill
  < lastname>Brogden
  < /user>

  当作为一个org.w3c.dom文档被解析到内存中时,firstname元素有一个是TEXT_NODE类型的子节点。程序员也许会被引导使用以下的Java代码来获得firstname字符串。

  // where fnE is the firstname org.w3c.dom.Element reference
   String name = fnE.getFirstChild().getNodeValue();

  使用类似的代码来设置firstname的新值。

    fnE.getFirstChild().setNodeValue( newfirstname );

  这段代码将会被编译并看起来能正确的工作,直到有一天由于某种原因一个空字符串被负值给了这个文本节点。当该文本仍然在内存中时,上面的代码将会继续工作。但是当该文档被一个转换器序列化为一个文档的时候,被序列化的并不是所期望的文档:

    < firstname>< /firstname>

  实际上你能得到的是:

    < firstname/>

  转换器意识到firstname元素为空,并考虑了这种首选的形式。现在当这个校订的文档再次被解析进入内存的时候,那个firstname元素就不再含有一个子节点,并且下面这个语句——

    String f = fnE.getFirstChild().getNodeValue();

  ——只会给程序员一个令人厌恶的打击,导致一个NullPointerException异常

  解决的办法当然就是防御性的进行编码,确认子节点的 存在并证明它的默认值不存在。例如,使用下面的代码来获得firstname。

   // where fnE is the firstname org.w3c.dom.Element reference
    Node fnNode = fnE.getFirstChild();
    if( fnNode == null ){  name= "" ;
    } else { name = fnNode.getNodeValue();
    }

  当子节点不存在时设置一个firstname的值需要更加复杂的代码,因为我们需要首先创建这个节点。

    Node fnNode = fnE.getFirstChild();
    if( fnNode == null ){
     Document doc = fnE.getOwnerDocument();
     fnNode = doc.createTextNode( newfirstname) ;
     fnE.appendChild( fnNode );
  } else {
     fnNode.setNodeValue( newfirstname );
  }

  为什么我的文档是空的?

  一些程序员已经习惯了使用以下的方式来编写代码,即在一个方法中把XML、解析为一个Document对象,从而确保这些Document本身已经被创建。

  // where builder is an instance of DocumentBuilder
  Document doc = builder.parse( f );
  System.out.println("Document is:" + doc );

  使用Java1.5 XML库,输出的结果如下所示:

  Document is:[#document: null]

  对一个新的程序员这看起来似乎是说Document没有内容。实际上它要表达的是你已经真正的有了一个Document对象我总是发现节点接口的Javadocs表对这种情况总是一个很大的帮助。它告诉你的是从getNodeValue和getNode命名的方法所能期望获得的是不同的DOM对象。这是一个Sun的为org.w3c.dom节点的在线文档的链接:http://java.sun.com/j2se/1.5.0/docs/api/org/w3c/dom/Node.html.

  从这张表你可以看到getNodeValue()方法总是从一个Document类型节点饭或空值。文档的toString()方法把"#document"名同从getNodeValue()得到的值结合起来。

  Unicode错误

  你在处理XML文档时会经常遇到的一个令人沮丧的错误是无效。Unicode字符错误将会产生一个如下所示的异常报告:

  org.xml.sax.SAXParseException: An invalid XML character (Unicode: 0x1a) was found in the element content of the document.

  或者是更为严重的警告:

  java.io.UTFDataFormatException: Invalid byte 1 of 1-byte UTF-8 sequence.

  找出无效字符的来源是一个极富挑战的侦探工作,特别是这些字符也许在通常的检测中都是很正常的。

  0x1a字符在一些特定的应用程序中被用作一个表示文件结束的标志的控制编码。在某种情况下,该字符在一个数据库域中结束并且接下来同不适宜的结果被插入到一个XML文档中去。

  一个通常的无效字符的来源通常是一些文档,这些文档是用微软的转换为“smart”标点的文档处理器生成的。如果你能看见打开和关闭引用的不同字符,你就有了"smart"标点。

  不幸的,微软选择了那些再0x82到0x95之间的字符作为"smart"标点,这些是Unicode保留作为控制编码的,并且在XML中是不合法的。从而当微软的文档作为XML文档进行粘贴和裁减操作的来源使用时,可能会导致引入阻止文档被解析的字符的危险。

  如果你有一个SAXParseException,你可以摘录异常中的那些令人不快的位置的代码,如下所示:

   }catch(SAXParseException spe ){
    String err = spe.toString() +
       "n  Line number: " + spe.getLineNumber() +
       "nColumn number: " + spe.getColumnNumber()+
       "n Public ID: " + spe.getPublicId() +
       "n System ID: " + spe.getSystemId() ;
    System.out.println( err );
 }

  如果你有一个程序编辑器也会是一个很大的帮助,特别是如果这个编辑器能够在显示正常的文本和以16进制显示的字符编码之间切换。我个人的更喜欢采用UltraEdit-32作为这种侦探工作的工具。

相关推荐

  • BEST:SOAP/XML和REST的替代方案

    虽然拥有大量的机架服务器,以及大量软件开发人员的组织,基于web和集成服务的SOAP和REST很适合他们,但也会出现问题。

  • Spring 烂!差!

    有些人可能对Spring的第一印象不太好,它真的很烂,很差吗,也许这只是你的一种偏见,它也有是自己的优点的。

  • 基于SOA架构的业务安全性研究

    SOA在提供价值链上企业之间信息共享和业务流程自动化的同时,也给业务信息安全带来了负面影响,且存在安全隐患,这些你知道吗?

  • Java读取配置文件的几种方法

    在现实工作中,我们常常需要保存一些系统配置信息,大家一般都会选择配置文件来完成,那么在Java怎样读取配置文件呢?