IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope:Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  XML  >

将 Atom 文档转换为 JSON

在将 Atom 转换为 JSON 时避免丢失重要数据和上下文

developerWorks
文档选项

未显示需要 JavaScript 的文档选项

讨论

英文原文

英文原文


级别: 中级

James Snell (jasnell@us.ibm.com), 软件工程师, IBM 

2008 年 1 月 25 日

初看起来,将 Atom 文档转换为 JSON 似乎非常简单。毕竟,Atom 只是一些 XML,并且有大量 XML 和 JSON 转换工具可用。然而,Atom 格式不仅仅是 XML 元素和属性的集合。许多复杂的细节使得很难正确处理 Atom。本文将描述这些问题,并演示了一种由 Apache Abdera 项目实现的机制,该机制可以将 Atom 文档转换成 JSON 并生成易于理解、易于使用的完整内容。

在将一个 Atom 文档转换为 JSON 时,将获得大量富含信息的内容,并将其序列化为一种非常简单的形式。在难于解析和正确处理 XML 的环境中,您可以更加轻松地使用这种更简单的内容形式。这个过程面临的主要挑战是,确保重要数据和上下文不会在转换过程中丢失。以下章节将讨论转换 Atom 文档时的各个关键问题。假设读者至少对 Atom 和 JSON 有一个基本的了解。如果对它们都不熟悉,请在继续阅读之前查看一下本文末尾列出的 参考资料

语言元数据

Atom 文档包含一个人类和计算机都能识别的混合信息集合。人类可读内容的恰当呈现,如条目标题、分类标签、链接标题、权限描述等等,依赖于一种在转换为 JSON 过程中必须正确保存的语言上下文。

xml:lang 是一种指定 Atom 文档所使用语言的机制。此属性可以出现在 Atom 文档中的任何位置,而且既可以被子元素继承,也可以被覆盖。xml:lang 属性的值是一个由 RFC 4646 定义的 “语言标记” ,名为 “Tags for Identifying Languag”。这些标记提供关于文本编写所用语言、使用的脚本或编写系统的信息,以及地区性语言变化等。这类信息将影响用户代理呈现文本的方式。

清单 1 所示的示例 Atom 提要演示了 xml:lang 在 Atom 文档中的用法,但是该示例没有实际意义。


清单 1. 使用 xml:lang 的 Atom 提要
                
<feed xmlns="http://www.w3.org/2005/Atom" 
      xml:lang="en-US"> 
  <title>This is the title</title>
  ... 
  <entry xml:lang="fr"> 
    ... 
    <category term="foo" label="bar" xml:lang="en" /> 
    <category term="goo" label="baz" />

    ... 
  </entry> 
</feed>

feed 元素上的 xml:lang 属性为整个文档建立默认的语言上下文。如果该元素的任何后代元素没有显式覆盖 xml:lang 属性(例如,提要的 title 元素),那么将自动继承此语言。

在 JSON 序列化过程中,可以将 xml:lang 属性转换为一个字段,从而捕获语言上下文。转换规则非常简单:当语言上下文发生改变时输出一个 lang 字段。清单 2 显示了 清单 1 中的提要的序列化过程。注意,只针对提要、条目和一级分类输出 lang 字段,标题和二级分类不会输出 lang 字段;因为后两种元素继承其父元素的语言。


清单 2. 对清单 1 中的提要进行序列化
                
{ 
  "lang":"en-US", 
  "title":"This is the title",
  "entries":[ 
    { 
      "lang":"fr" 
      "categories":[ 
        { 
          "lang":"en", 
          "term":"foo", 
          "label":"bar" 
        }, 
        { 
          "term":"goo", 
          "label":"baz" 
        } 
      ] 
    } 
  ] 
}
            

任何元素,只要其子元素或属性被认为是语言敏感 的,都可以包含 xml:lang 属性。在核心 Atom 词汇表中,这个集合包括 feed、entry、title、rights、subtitle、summary、content、category、link、author 和 contributor。





回页首


IRI 和 URI

除支持多种语言外,Atom 还支持使用国际化资源标识符(Internationalized Resource Identifier,IRI)。IRI 是一个允许包含非 ASCII 字符的 URI。

当设计一个 Atom 到 JSON 的序列化时,区分 IRI 在 Atom 文档中的两种用法非常重要。在清单 3 所示的示例中,有 4 个元素包含了 IRI。


清单 3. 包含多个国际化资源标识符的提要
                
<feed xmlns:a="http://www.w3.org/2005/Atom" 
        xml:base="http://examplé.org/foó"> 
  ... 
  <id>http://examplé.org/foó</id>
  <link rel="self" href="" /> 
  <link href="/blog" /> 
  <category scheme="http://examplé.org/foó/bar" term="foo" />
  ... 

</feed>
			

idcategory 元素使用 IRI 作为标识符。尽管这些标识符与普通的 URL 很相似,但它们并不能被解除引用。Atom 要求按这种方式使用的 IRI 必须是绝对 IRI,而且通常把它们当作不需要 Atom 用户进行额外处理的 opaque 值。在 Atom 词汇表中,idcategory 是惟一将 IRI 用作标识符的元素。

然而,link 元素是专门用于提供对某个其他资源的引用。href 属性用来指定一个可被解除引用的 IRI。该属性的值可以是一个相对路径 ,而且必须由 Atom 用户处理并生成正确的结果。这个处理过程包括将 IRI 转换为一个等价的 URL。在核心 Atom 词汇表中,icon、logo、uri、link 和 content 元素可以包含能被解除引用的 IRI。

清单 4 显示了 idcategory 元素的 JSON 序列化。注意,这些 IRI 是按原样复制的,没有经过额外处理。


清单 4. 清单 3 中的 id 和 category 元素的 JSON 序列化
                
"id":"http://examplé.org/foó" 
"categories":[
  {
    "scheme":"http://examplé.org/foó/bar", 
    "term":"foo"
  }
]

另一方面,可解除引用的 IRI,需要被解析为完全限定的绝对路径,并转换为通常能够在 JSON 中使用的 URL,清单 5 中将演示这一过程。注意,“http://xn--exampl-gva.org/fo%C3%B3” 是与 IRI “http://examplé.org/foó” 等价的 ASCII URL。


清单 5. 清单 3 中的 link 元素的 JSON 序列化
                
"links":[ 
  { 
    "rel":"self", 
    "href":"http://xn--exampl-gva.org/fo%C3%B3" 
  }, 
  { 
    "href":"http://xn--exampl-gva.org/blog" 
  } 
] 

应该同等对待 Atom 文档任意位置出现的可解除引用的 IRI 或 URI,特别是当它们出现在文本结构和内容的 HTML 和 XHTML 标记中时,如清单 6 所示。


清单 6. 包含相对 URI 路径的 XHTML 标记
                
<a:content type="xhtml"> 
  <div> 
    <img src="/images/foo.jpg" /> 
  </div> 

</a:content>
     

由于 JSON 不能保持任何 Base URI 概念,所以使用 JSON 序列化的应用程序不可能正确呈现包含相对 URI 路径的标记。因此,在转换过程中对这类路径进行自动转换非常重要,如清单 7 所示。


清单 7. 清单 6 中的 XHTML 标记的 JSON 序列化
                
"content":{ 
  "attributes":{ 
    "type":"xhtml" 
  }, 
  "children":[ 
    { 
      "name":"img", 
      "attributes":{ 
        "src":"http://example.org/images/foo.jpg" 
      }, 
      "children":[] 
    } 
  ] 
}
     

很明显,这需要生成序列化 JSON 输出的应用程序能够正确解析 HTML 和 XHTML 标记,并挑选出其值可能是 URI 的属性。





回页首


可重复元素

Atom 词汇表中的一些元素能够在一个提要或条目中出现多次。在 JSON 序列化中,这些元素会呈现为清单 8 和 9 中演示的 Array。


清单 8. Atom feedentrysource 元素可以包含多个 atom:author 元素
                
<author> 
  <name>James M Snell</name> 
</author> 
<author> 
  <name>Jane Doe</name> 

</author>
     


清单 9. 清单 8 中的 author 元素的 JSON 序列化
                
"authors":[
  {
    "name":"James M Snell",
  },
  {
    "name":"Jane Doe",
  }
]
     

在 Atom 词汇表中,authorcontributorcategorylinkentry 元素都是可重复出现的。清单 10 到 13 进一步演示了将可重复出现的元素转换为 JSON 数组的过程。这些示例非常简单明了,因此不作赘述。


清单 10. 多个 Atom category 元素
                                
<category term="foo" 
  scheme="http://example.org/categories/" />

<category term="bar" 
  scheme="http://example.org/categories/" 
  label="Bar" />
     


清单 11. 清单 10 中的多个 category 元素的 JSON 序列化
                                
"categories":[
  {
    "term":"foo",
    "scheme":"http://example.org/categories/"
  },
  {
    "term":"bar",
    "scheme":"http://example.org/categories/", 
    "label":"Bar"
  }
]
     


清单 12. 多个 Atom link 元素
                                
<link href="/foo" 
      rel="related" 
      title="Related Entry"
      type="text/html" />
<link href="/bar" 
      title=”Alternate View"
      type="text/html" />
      


清单 13. 清单 12 中多个 link 元素的 JSON 序列化
                                
"links":[
  {
    "href":"http://example.org/foo",
    "rel":"related",
    "title":"Related Entry",
    "type":"text/html"
  },
  {
    "href":"http://example.com/bar",
    "title":"Alternate View",
    "type":"text/html"
  }
]
     





回页首


日期

在 Atom 中使用 RFC 3339 指定的 ISO 8601 格式的一个子集表示日期和时间。清单 14 展示了一个 Atom updated 元素的示例。


清单 14. Atom updated 元素中的 RFC 3339 日期-时间
                                
<updated>2007-10-14T12:12:12Z</updated>
     

根据 JSON 的数据输入模型,在序列化日期时,选择非常有限。我可以:

  • 将日期转换为一个数值,表示从 1970 年 1 月 1 日 00:00:00 UTC 开始经过的秒数(例如,一个标准的 UNIX® 时间戳)
  • 将日期转换为日期的 JavaScript toString 序列(例如,2007 年 10 月 21 日 星期日 12:34:28 GMT-0700 (PDT))
  • 按日期在 Atom 文档中的呈现形式对其进行复制。

前两个选项可以在 JavaScript 中处理,不需要开发人员做太多的工作。也就是说,要获得正确的 JavaScript Date 对象,只需调用新的 Date(feed.updated)。但是,其缺点是,使用第一个选项会丢失与毫秒数和时区偏移有关的重要信息;如果使用第二个选项,日期的 toString 序列会因实现和地区的不同而不同。尽管使用 RFC 3339 序列需要额外的工作,但这是避免数据丢失和数据含义不明的惟一选项。


清单 15. 清单 14 中的 updated 元素的 JSON 序列化
                
"updated":"2007-10-14T12:12:12.000Z"
     

清单 16 中的 JavaScript 代码解析 RFC 3339 日期-时间并生成一个合适的 JavaScript date 对象。


清单 16. 解析 Atom 中使用的 RFC 3339 日期-时间的 JavaScript 代码
                                
AtomDate = Class.create(); 
AtomDate.pattern = /^(\d{4})(?:-(\d{2}))?(?:-(\d{2}))?(?:[Tt]   \
  (\d{2}):(\d{2}):(\d{2})(?:\.(\d*))?)?([Zz])?(?:([+-])(\d{2}):(\d{2}))?$/; 
AtomDate.localoffset = (new Date()).getTimezoneOffset(); 
AtomDate.padding = function(val,char,count) { 
  var value = ""; 
  while(count > 0) { 
    if (val < Math.pow(10,count)) value = char + value; 
    count--; 
  } 
  return value + val; 
} 
AtomDate.parse = function(val) { 
  if (!val) throw "Invalid Date"; 
  if (val instanceof Date) return val; 
  var m = AtomDate.pattern.exec(val); 
  var year = new Number(m[1]?m[1]:0); 
  var month = new Number(m[2]?m[2]:0); 
  var day = new Number(m[3]?m[3]:0); 
  var hour = new Number(m[4]?m[4]:0); 
  var minute = new Number(m[5]?m[5]:0); 
  var second = new Number(m[6]?m[6]:0); 
  var millis = new Number(m[7]?m[7]:0); 
  var gmt = m[8]; 
  var dir = m[9]; 
  var offhour = new Number(m[10]?m[10]:0); 
  var offmin = new Number(m[11]?m[11]:0); 
  
  if (dir && offhour && offmin) { 
    var offset = ((offhour * 60) + offmin); 
    if (dir == "+") { 
      minute -= offset; 
    } else if (dir == "-") { 
      minute += offset; 
    } 
  } 
  return new Date(Date.UTC(year,month,day,hour,minute,second,millis)); 
}

Object.prototype.value2date = function() { 
  return AtomDate.parse(this); 
}
     

任何字符串,只要其值是一个 RFC 3339 日期,value2date 函数就能够获得这个值并作为一个 JavaScript Date 对象。

注意:出于格式化的目的,AtomDate.pattern 正则表达式被分解为多行。


清单 17. 使用清单 16 中的日期解析代码
                                     
document.write(m.updated.value2date());
     





回页首


文本结构

Atom 支持大量的文本和内容选项,到目前为止,这是在 JSON 序列化过程中碰到的最复杂最困难的问题。文本结构,比如 title、subtitle、summary 和 rights 元素,可以包含纯文本、转义 HTML 或 XHTML 标记;这些结构具有语言敏感性,因此必须考虑 xml:lang 属性;而且 HTML 和 XHTML 标记可以包含需要解析的相对 URI。由于 Atom content 元素支持 Base64 编码的内容、任意 XML 标记和使用 src 属性引用的外部内容,这使得序列化过程更加困难。

对 Atom 内容进行 JSON 序列化的目的是找到一种通用的表示方法,该方法能够尽可能一致地捕获这些选项。清单 18 展示了一个带有 3 种文本结构的提要示例。


清单 18. 带有 3 种不同类型的文本结构的 Atom feed 元素
                                
<feed xmlns="http://www.w3.org/2005/Atom"> 
  ...
  <title>Example Feed</title>
  <subtitle type="html"><p>This is an example feed</p></subtitle>

  <rights xml:lang="fr">...</right>
  ...
</feed>
     

title 元素为纯文本。它需要继承提要的语言上下文,否则不具备描述性。subtitle 元素包含转义的 HTML 标记。right 元素也是纯文本,但它覆盖了语言上下文。清单 19 展示了这 3 个元素的 JSON 序列化。


清单 19. 清单 18 中的文本结构的 JSON 序列化
                                

{
  "title":"Example Feed", 
  "subtitle":{ 
    "attributes":{ 
      "type":"html" 
    }, 
    "children":[
      { 
        "name":"p", 
        "attributes":{ }, 
        "children":["This is an example feed" ] 
      } 
    ]
  },
  "rights":{
    "attributes":{
      "lang":"fr"
    },
    "children":[
      "..."
    ]
  } 
}
     

注意,这只是最简单的情形,title 被序列化为一个简单字符串。但是,由于 right 元素中的语言上下文时刻都会变化,所以尽管它是纯文本,也被序列化为包含两个字段(attributes 和 children)的对象。

对于 subtitle 元素,HTML 标记被解析并呈现为一种分层结构。XHTML 标记也使用相同的结构(清单 20 和 21)。


清单 20. 使用 XHTML 标记的文本结构
                                
<subtitle type="xhtml">
  <div xmlns="..."><p>This is an example feed</p></div>

</subtitle>
     


清单 21. 清单 20 中的 XHTML 标记的 JSON 序列化
                                
"subtitle":{ 
  "attributes":{ "type":"xhtml" }, 
  "children":[
    { 
      "name":"p", 
      "attributes":{ }, 
      "children":["This is an example feed" ] 
    }
  ] 
}
     

此结构确保以一种没有歧义的、一致的方式对纯文本和标记内容进行序列化。但是,其缺点是,与编写一个简单的 document.write(...) 或在一个 div 上设置 innerHTML 属性相比,在 Web 浏览器中显示内容要更加复杂。我们需要一种方法将解析得到的结构转换为一种易于显示的形式。

清单 22 对最初由 Sam Ruby 提供的代码进行了修改,包含 Atom 文本结构或内容元素的 JSON 序列化,并将其转换为一个字符串。


清单 22. JavaScript 将经过 JSON 序列化的文本结构重新构造为可显示的字符串值
                                

Array.prototype.hash2value = function () { 
  var result = ''; 
  for (var i=0; this.length>=i; i++) if (this[i]) result+=this[i].tag2value(); 
  return result; 
} 

Object.prototype.tag2value = function () { 
  if (this.name) { 
    var result = String.fromCharCode(60) + this.name; 
    for (key in this.attributes) { 
      if (typeof(this.attributes[key]) === 'function') continue; 
      result += ' ' + key + '="' + this.attributes[key].toString() + '"'; 
    } 
    result += '>' + this.children.hash2value(); 
    result += String.fromCharCode(60) + '/' + this.name + '>'; 
    return result; 
  } else return this.toString(); 
}

Object.prototype.value = function() { 
  if (this.children) return this.children.hash2value(); 
  else return this.toString(); 
} 

Array.prototype.value = function() { 
  var result = ''; 
  for (var i = 0; this.length>=i; i++) 
    if (this[i]) result+=this[i].value(); 
  return result; 
}
     

添加到 JavaScript Array 和 Object 类的 value 函数使得可以使用 hash2value 函数,而不需要考虑某个特定对象是否被序列化为简单字符串或对象结构。


清单 23. 使用清单 22 中的 JavaScript 代码显示经过 JSON 序列化的文本
                                
document.write(m.title.value()); 
document.write(m.subtitle.value()); 
document.write(m.rights.value());
     

使用此处提供的模型处理 atom:content 元素中的扩展内容类型与处理纯文本、HTML 或 XHTML 并无二致。清单 24 展示了 4 种经过扩展的内容示例,演示了备选的媒体类型、任意格式良好的 XML、Base64 编码的二进制数据和使用 src 属性的引用内容的用法。


清单 24. 经过扩展的内容类型示例
                                     
<content type="text/plain">This is plain text</content>

<content type="application/xml"><a xmlns="foo">b</a></content>

<content type="image/jpg">{base64 encoded data}</content>

<content type="image/jpg" src="image.jpg" />
     

清单 25 展示了这些形式的内容的 JSON 序列化。


清单 25. 清单 24 中经过扩展的内容类型的 JSON 序列化
                                
"content":{ 
  "attributes":{ "type":"text/plain" }, 
  "children":["This is plain text" ] 
} 

"content":{
  "attributes":{ "type":"application/xml" },
  "children":[
    {
      "name":"a",
      "attributes": {
        "xmlns":"foo"
      },
      "children":["b"]
    }
  ]
}

"content":{ 
  "attributes":{ "type":"image/jpg" }, 
  "children":["{base64 encoded data}" ] 
} 

"content":{ 
  "attributes":{ 
    "type":"image/jpg", 
    "src":"http://example.org/image.jpg" 
  }, 
  "children":["" ] 
} 
     





回页首


扩展

将 Atom 序列化为 JSON 需要考虑的最后一个问题是,如何处理扩展。有 3 种可能的选择:

  • 忽略所有扩展,而且不要将它们包含在 JSON 序列化中
  • 序列化已知扩展,忽略其他所有扩展
  • 序列化所有扩展

第一种选择显然是最简单的选择,但是限制了 JSON 表示的整体效用(并不一定是件坏事)。第二种选择允许对已知扩展的 JSON 序列化进行优化和简化,但是仍然限制了序列化的效用。第三种选择显著增加了序列化的总体复杂性,但是能够确保原始 Atom 文档的所有信息都能够通过 JSON 表示出来。

首先讨论如何优化已知扩展的输出。Atom Threading Extension (RFC 4685) 提供了一种方法,可以表示某个条目是另一个条目的响应。主题扩展规范明确指定了 in-reply-to 元素的属性和含义,并表示多个 in-reply-to 元素可以出现在同一个条目中。了解了这一点,就可以对 in-reply-to 元素的 JSON 表示进行优化,如清单 26 和 27 所示。


清单 26. 在 Atom 条目中使用 Atom Threading Extension
                                
<entry>
  ...
  <thr:in-reply-to ref="tag:example.org,2007:/foo/entries/2" />
  <thr:in-reply-to ref="tag:example.org,2007:/foo/entries/3" />
  ...

</entry>
     


清单 27. 清单 26 中的 Atom Threading Extension 的 JSON 序列化
                                
 "inreplyto":[
   { 
     "ref":"tag:example.org,2007:/foo/entries/2" 
   },
   {
     "ref":"tag:example.org,2007:/foo/entries/3"
   }
 ]
     

然而,对于未知的扩展,需要使用更加详细和一般化的语法捕获所有必需细节。清单 28 展示了一个带有复杂的未知扩展元素的条目示例。


清单 28. Atom 条目中复杂的未知扩展
                                
<entry>

  ...
  <foo:a xmlns="..."><foo:b><foo:c d="e">f</foo:c></foo:b></foo:a>
  ...
</entry>
     

该扩展的序列化(清单 29)方法与由 HTML 或 XHTML 标记组成的文本的序列化方法相同。


清单 29. 对清单 28 中的扩展进行 JSON 序列化
                                
"extensions":[
  {
    "name":"foo:a", 
    "attributes":{ 
      "xmlns:foo":"http://example.org/unknown-markup" 
    }, 
    "children":[
      { 
        "name":"foo:b", 
        "attributes":{ }, 
        "children":[
          { 
            "name":"foo:c", 
            "attributes":{ "d":"e" }, 
            "children":["f" ]
          }
        ]
      }
    ]
  }
]
     





回页首


文档转换

现在,可以获取任何 Atom 文档并将其转换为有用的 JSON 表示。清单 30 和 31 提供了转换过程的完整演示。原始 Atom 文档包含相对 IRI、语言上下文、扩展、多种文本和内容类型等。使用从 Internet 上获得的任何 XML 和 JSON 转换器运行此文档,产生的序列化都不可避免地遇到数据丢失和/或可用性问题。


清单 30. 完整的 Atom 提要文档
                                
<?xml version="1.0" encoding="utf-8" ?> 

<a:feed xmlns:a="http://www.w3.org/2005/Atom" 
        xmlns:thr="http://purl.org/syndication/thread/1.0" 
        xmlns="http://www.w3.org/1999/xhtml" 
        xmlns:foo="http://example.org/unknown-markup" 
        xml:lang="en-US" 
        xml:base="http://example.org/foo" 
        dir="ltr"> 
  
  <a:id>tag:example.org,2007:/foo</a:id> 
  <a:title>Example Feed</a:title> 
  <a:subtitle type="html"><![CDATA[<p>This is an example feed</p>]]></a:subtitle> 
  <a:rights type="xhtml">

    <div>
      <p>Copyright © James M Snell</p>
    </div>
  </a:rights> 
  <a:author xmlns="http://www.w3.org/2005/Atom"> 
    <name>James M Snell</name> 
    <email>jasnell@example.org</email> 
    <uri>/~jasnell</uri> 
  </a:author> 
  <a:updated>2007-10-14T12:12:12Z</a:updated> 
  <a:link rel="self" href="" /> 
  <a:link href="/blog" /> 
  <a:link rel="alternate" type="application/json" href="/blog;json" /> 
  
  <a:entry xml:base="entries/1"> 
    <a:id>tag:example.org,2007:/foo/entries/1</a:id> 
    <a:title type="text">Entry Number One</a:title> 
    <a:summary type="xhtml"> 
      <div> 
        <p>This is the first entry. You can read it <a href="">here</a></p> 
      </div> 
    </a:summary> 
    <a:rights type="html">

      <p>Copyright &copy; James M Snell</p>
    </a:rights> 
    <a:updated>2007-10-14T12:12:12Z</a:updated> 
    <a:link href="" /> 
    <a:link rel="alternate" type="application/json" href="1;json" /> 
    <a:link rel="replies" type="application/atom+xml" 
      href="1;replies" thr:count="10" /> 
    <a:content type="xhtml"> 
      <div> 
        <p>This is the content of the first entry. It contains a picture.</p> 
        <img src="/images/foo.jpg" /> 
      </div> 
    </a:content> 
    <thr:in-reply-to ref="tag:example.org,2007:/foo/entries/2" /> 
    <a:category scheme="http://example.org/categories/" term="foo" 
      label="test" xml:lang="en-US" /> 
    <a:category scheme="http://example.org/categories/" term="bar" 
      label="essai" xml:lang="fr" /> 
    <foo:a><foo:b><foo:c d="e">f</foo:c></foo:b></foo:a> 
  </a:entry> 
 
  <a:entry xml:base="entries/2" xml:lang="fr"> 
    <a:id>tag:example.org,2007:/foo/entries/2</a:id> 
    <a:title type="text">La première entrée</a:title> 
    <a:summary type="xhtml"> 
      <div> 
        <p>Il s'agit de la première entrée. Vous pouvez lire 
        <a href="">est ici</a></p> 
      </div> 
    </a:summary> 
    <a:rights type="html">

      <p>Copyright &copy; James M Snell</p>
    </a:rights> 
    <a:updated>2007-10-14T12:12:11Z</a:updated> 
    <a:link href="" /> 
    <a:link rel="alternate" type="application/json" href="2;json" /> 
    <a:link rel="replies" type="application/atom+xml" 
      href="2;replies" thr:count="10" /> 
    <a:content type="xhtml"> 
      <div> 
        <p>Ceci est le contenu de la première entrée. Il contient une image.</p> 
        <img src="/images/foo.jpg" /> 
      </div> 
    </a:content> 
    <thr:in-reply-to ref="tag:example.org,2007:/foo/entries/1" /> 
    <a:category scheme="http://example.org/categories/" term="foo" 
      label="test" xml:lang="en-US" /> 
    <a:category scheme="http://example.org/categories/" term="bar" 
      label="essai" xml:lang="fr" /> 
    <foo:a><foo:b><foo:c d="e">f</foo:c></foo:b></foo:a> 
  </a:entry> 

</a:feed>
     

本文描述的从 Atom 到 JSON 的序列化技术能够生成一个容易理解、易于使用而且能够避免丢失重要上下文数据的 JSON 表示。


清单 31. 对清单 30 中完整的 Atom 提要文档进行 JSON 序列化
                                
{ 
 "lang":"en-US", 
 "dir":"ltr", 
 "id":"tag:example.org,2007:/foo", 
 "title":"Example Feed", 
 "subtitle":{ 
  "attributes":{ 
   "type":"html" 
  }, 
  "children":[{ 
    "name":"p", 
    "attributes":{ }, 
    "children":["This is an example feed" ] 
   } ] }, 
 "rights":{ 
  "attributes":{ "type":"xhtml" }, 
  "children":[{ 
    "name":"p", 
    "attributes":{ }, 
    "children":["Copyright \u00a9 James M Snell" ] 
   } ]}, 
 "updated":"2007-10-14T12:12:12.000Z", 
 "authors":[{ 
   "name":"James M Snell", 
   "email":"jasnell@example.org", 
   "uri":"http://example.org/~jasnell" 
  } ], 
 "links":[
   { 
     "href":"http://example.org/foo", 
     "rel":"self" 
   },
   { 
     "href":"http://example.org/blog" 
   },
   { 
     "href":"http://example.org/blog;json", 
     "rel":"alternate", 
     "type":"application/json" 
   } ], 
 "entries":[...],
 "attributes":{ 
  "xml:lang":"en-US", 
  "xml:base":"http://example.org/foo" 
 }
}
     





回页首


使用 Abdera JSON Writer

本文介绍的技术已经作为 Apache Abdera 项目的一部分实现了。清单 32 中的代码演示了 Abdera JSON Writer 的使用。如果想要尝试 Atom 到 JSON 的转换,请访问 Abdera wiki,获取关于如何下载最新开发映像的信息。


清单 32. 使用 Apache Abdera JSON Writer
                                
Abdera abdera = new Abdera();
Entry entry = abdera.newEntry();
    
entry.setId("http://example.org");
entry.setTitle("Testing the JSON Writer");
entry.setUpdated(new Date());
entry.addLink("http://www.example.org");
entry.addAuthor("James Snell");
entry.setSummary("This is a test of the JSON Writer");
    
entry.writeTo("json", System.out);
   

分享这篇文章……

digg 提交到 Digg
del.icio.us 发布到 del.icio.us
Slashdot Slashdot 一下!





回页首


结束语

将数据从一种格式转换成另一种格式总是一个很困难的任务。将 Atom 这样丰富和强大的数据格式序列化为 JSON 这类简单的基本格式,一定会面临许多问题。尽管已经有许多出色的尝试,在出现标准的转换方法之前,应用程序开发人员需要处理多种质量参差不齐的不兼容序列化方法,本文描述的技术只是其中的一种。



参考资料

学习
  • 您可以参阅本文在 develperWorks 全球网站上的 英文原文

  • RFC 4287:查阅关于 Atom Syndication Format 的更多信息。这是一个基于 XML 的文档格式,描述将 webblog 和新闻标题连锁到 Web 站点,以及直接连锁到用户代理的提要。

  • RFC 4627:在这个详细的 IETF 备忘录中了解 JSON Format 的更多信息。

  • Apache Abdera wiki:了解关于 Abdera 项目和开发支持 Atom 的 Java 应用程序的更多信息。

  • Google 的 GData API:了解将 Atom 转换为 JSON 的一种可选方法。

  • IBM XML 认证:了解如何成为一名 IBM 认证的 XML 和相关技术的开发人员。

  • XML 技术文档库:访问 developerWorks XML 专区,获取广泛的技术文章和技巧、教程、标准和 IBM 红皮书。

  • developerWorks 技术活动和网络广播:随时关注这些领域的最新技术。

  • 技术书店:浏览关于这些主题和其他技术主题的图书。

  • XML 新手入门 (New to XML) 页面:查阅 XML 专区中最新的 XML 资源。

获得产品和技术
  • IBM 试用版软件:使用试用软件构建下一个开发项目,可直接从 developerWorks 下载获得。


讨论


关于作者

Photo of James M Snell

James Snell 是 IBM WebAhead 开发实验室的成员,主要研究前沿性软件技术的原型开发和 IBM 自己使用的标准。他的研究和开发方向涉及到当前的各种技术趋势,包括 Atom、AJAX、REST、开放源码、个人发布系统、语义 Web 和语境应用程序。他积极参与 Apache Abdera 项目,目前正在筹划创建 Atom Syndication Format 和 Atom Publishing Protocol 高性能、功能完善的实现。




对本文的评价

太差! (1)
需提高 (2)
一般;尚可 (3)
好文章 (4)
真棒!(5)

将您的建议发给我们或者通过参加讨论与其他人分享您的想法.




回页首


IBM、DB2、Rational 和 pureXML 是 IBM Corporation 在美国和/或其他国家的商标。 Java 和所有基于 Java 的商标是 Sun Microsystems, Inc. 在美国和/或其他国家的商标。 Microsoft、Windows 和 Windows 徽标是 Microsoft Corporation 在美国和/或其他国家的商标 Linux 是 Linus Torvalds 在美国和/或其他国家的商标。 其他公司、产品或服务的名称可能是其他公司的商标或服务标记。 其他公司、产品或服务的名称可能是其他公司的商标或服务标志。

IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款