惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
雷峰网
雷峰网
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Spread Privacy
Spread Privacy
H
Hacker News: Front Page
PCI Perspectives
PCI Perspectives
Webroot Blog
Webroot Blog
罗磊的独立博客
H
Heimdal Security Blog
TaoSecurity Blog
TaoSecurity Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
大猫的无限游戏
大猫的无限游戏
月光博客
月光博客
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Google Online Security Blog
Google Online Security Blog
Last Week in AI
Last Week in AI
美团技术团队
Help Net Security
Help Net Security
The Hacker News
The Hacker News
C
Cisco Blogs
T
The Blog of Author Tim Ferriss
J
Java Code Geeks
The Register - Security
The Register - Security
IT之家
IT之家
WordPress大学
WordPress大学
Jina AI
Jina AI
Recent Commits to openclaw:main
Recent Commits to openclaw:main
H
Help Net Security
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
Threat Research - Cisco Blogs
P
Proofpoint News Feed
NISL@THU
NISL@THU
爱范儿
爱范儿
The GitHub Blog
The GitHub Blog
Scott Helme
Scott Helme
V
Vulnerabilities – Threatpost
B
Blog
T
Tenable Blog
博客园 - 三生石上(FineUI控件)
T
The Exploit Database - CXSecurity.com
S
Security Affairs
小众软件
小众软件
Hacker News: Ask HN
Hacker News: Ask HN
Security Latest
Security Latest
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
W
WeLiveSecurity
A
Arctic Wolf
L
LINUX DO - 热门话题
Google DeepMind News
Google DeepMind News
M
MIT News - Artificial intelligence

博客园 - Wisdom-zh

【关注】“诋毁” 一下博客园的模板 混淆器【修正版】 发一个混淆器, Nuva 写的 Win32Ole 演示【控制 Word】 Win32Api 演示【控制任务栏】 通用数据浏览示例 方便的 XML 数据绑定 Swap 函数 延迟计算 短路运算 语法兼容 之 运算符总结 这是什么语言的代码 Nuva 语法兼容 之 控制结构总结 设计模式 之 状态机模式 Nuva 示例代码(每日一帖)之 源代码统计 Nuva 示例代码(每日一帖)之 数据架构提取 Nuva 示例代码(每日一帖)之 ShowMessage Nuva 示例代码(每日一帖)之 异常处理 Nuva 示例代码(每日一帖)之 语法兼容
挑战 XSLT 最擅长的 XML 文档转换
Wisdom-zh · 2006-09-08 · via 博客园 - Wisdom-zh

  XML 是描述数据的最佳语言,XML 是一个庞大的家族,因此很多人都极力的发掘 XML 的潜力,欲将其用至极致。 

  XSLT 的出现无疑大大加重了这样的倾向,因为 XSLT 中支持了众多的编程元素,所以对于 XML 文档的转换无疑采用 XSLT 是极为方便的。甚至有人采用 XSLT 作为模板来编写代码生成器。 

  本文将对这样对于 XML 的极致使用目标提出质疑,认为过分极致的使用目标就是“误用”,会使我们减少对于更适宜方案的选择。本文认为“物尽其用”不如“物用其宜”。
  
本文从一个简单的 XML 文档转换问题出发,给出采用传统的 XSLT 转换代码,并且针对这样的转换方案做出改进,采用一种新的编程语言 Nuva 语言(也可以采用其他编程语言)编写转换程序。两厢对比,相信读者不难看出,采用编程语言比 XSLT 这样的转换语言具有入门门槛低、程序更短、更易读以及更容易维护等众多的优点。

  考虑如下的源 XML 文档,该文档是 Microsoft .NET DataSet 对于 XML 的存档文件:

==【DotNetDataSet-Sample.xml】==

<?xml version="1.0" encoding="UTF-8"?>
<Schema1>
  <Table1>
    <Field11>A1</Field11>
    <Field12>A2</Field12>
  </Table1>
  <Table1>
    <Field11>B1</Field11>
    <Field12>B2</Field12>
  </Table1>
  <Table1>
    <Field11>C1</Field11>
    <Field12>C2</Field12>
  </Table1>
  <Table2>
    <Field21>D1</Field21>
    <Field22>D2</Field22>
    <Field23>D3</Field23>
  </Table2>
  <Table2>
    <Field21>E1</Field21>
    <Field22>E2</Field22>
    <Field23>E3</Field23>
  </Table2>
</Schema1>


 
现在欲将其转换成如下的 XML 文档,该文档是 Macrobject XObject 标准 XML 存档文件

==【ObjectSpace-Sample.xml】==

<?xml version="1.0" encoding="UTF-8"?>
<ObjectSpace Name="Schema1">
  <ObjectSet Name="Table1">
    <Object Field11="A1" Field12="A2" />
    <Object Field11="B1" Field12="B2" />
    <Object Field11="C1" Field12="C2" />
  </ObjectSet>
  <ObjectSet Name="Table2">
    <Object Field21="D1" Field22="D2" Field23="D3" />
    <Object Field21="E1" Field22="E2" Field23="E3" />
  </ObjectSet>
</ObjectSpace>


 
XML 文档是一种“长”结构,所有的字段都用单独的一个节点来表示,表的每一行分别表示,无论表是否相同,都相互没有关系,看起来比较费劲。另外其缺点是上下可能比较“长”。

  目标 XML 文档采用一种“宽”结构,字段都放在所属行(Object)的属性中,每一个表(ObjectSet)的所有行放在同一个节点下,所以很容易分表来看。缺点是左右可能比较“宽”。

  下面采用传统的 XSLT 来编写转换程序,如下:

==【DotNetDataSet2ObjectSpace.xslt】==

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/02/xpath-functions" xmlns:xdt="http://www.w3.org/2005/02/xpath-datatypes
"> <xsl:template match="/"> <xsl:apply-templates select="child::node()"/> </xsl:template> <xsl:template match="child::node()"> <xsl:element name="ObjectSpace"> <xsl:attribute name="Name"> <xsl:value-of select="fn:node-name(.)"/> </xsl:attribute> <xsl:variable name="ChildNodes" select="./*" /> <xsl:variable name="NodeNames"> <xsl:element name="Node"> <xsl:for-each select="$ChildNodes"> <xsl:attribute name="{fn:node-name(.)}"> <xsl:value-of select="'true'" /> </xsl:attribute> </xsl:for-each> </xsl:element> </xsl:variable> <xsl:variable name="DistinctNodes"> <xsl:for-each select="$NodeNames/@*"> <xsl:element name="{fn:name(.)}"> </xsl:element> </xsl:for-each> </xsl:variable> <xsl:for-each select="$DistinctNodes"> <xsl:element name="ObjectSet"> <xsl:attribute name="Name"> <xsl:value-of select="fn:node-name(.)" /> </xsl:attribute> <xsl:variable name="Name" select="fn:node-name(.)" /> <xsl:for-each select="$ChildNodes [fn:node-name(.) = $Name]"> <xsl:element name="Object"> <xsl:for-each select="./*"> <xsl:attribute name="{fn:node-name(.)}"> <xsl:value-of select="." /> </xsl:attribute> </xsl:for-each> </xsl:element> </xsl:for-each> </xsl:element> </xsl:for-each> </xsl:element> </xsl:template> </xsl:stylesheet>

  简单看一下,用 XSLT 写的转换程序比较复杂,而且也用了一些技巧,学起来比较费劲,老实说,我现在已经无法维护它了,因为时间一长,我已经不怎么看得懂了。

  后来,我转换了一下思维,用 Nuva 语言重写了一次,结果连我自己也吃了一惊,非常的简洁,如下:

<..========================================================
==                                                       ==
==                Macrobject Nuva Samples                ==
==                                                       ==
==      Copyright (c) 2004-2006 Macrobject Software      ==
==                                                       ==
==                  ALL RIGHTS RESERVED                  ==
==                                                       ==
==               http://www.macrobject.com               ==
==                                                       ==
========================================================..>
<.
  var sourceFile = 'DotNetDataSet-Sample.xml'

  var source = System.Xml.Document(sourceFile)
  var target = System.Xml.Document('ObjectSpace')

  target.Root.Props.Name = source.Root.Name
  foreach(sTable = source.Root.Nodes)
    var tObjSet = FindOrCreateObjectSet(target.Root, sTable.Name)
    var tObj = tObjSet.Nodes.Add('Object')
    foreach(sField = sTable.Nodes)
      tObj.Props[sField.Name] = sField.Value
    end foreach

    function FindOrCreateObjectSet(theParent, theName)
      Result = theParent.FindByProp('Name', theName)
      if (Result = nil)
        Result = theParent.Nodes.Add('ObjectSet')
        Result.Props.Name = theName
      end if
    end function
  end foreach

  ? target.ToString
.>

<..
【简介】
    本例是一个 XML 文档转换程序,本例的源 XML 文档是 Microsoft .NET 的 DataSet 存档为 XML 的文件,本例的目标 XML 文档是 Macrobject XObject 的 XML 存档文件。

    Microsoft .NET DataSet 信息请参考微软网站的相关内容:www.microsoft.com

    Macrobject XObject XML 是 Macrobject 所有 O/R Mapping 的标准存档格式,这个 XML 文件可以模拟一个简单的关系数据库,具体信息请参考 www.macrobject.com 的有关内容。

    本例演示了 Nuva 语言操纵 XML 文档的便利性,甚至超过了 XML 标准转换语言 XSLT。

【看点】
    1、本例演示了 Nuva 语言在 XML 的应用
       Nuva 语言提供了一个 XML 库,其中包括 XmlDocument、XmlNode、XmlNodeList 类:

       XmlDocument 对象通过 System.XML.Document([名称]) 创建,其中可以包含一个名称参数,如果该名称是一个文件,则从文件读取,否则返回的 XmlDocument 的 Root 节点即可以此名称来命名。

       XmlDocument 有一些属性和方法,具体可以参见<<Nuva API>>,本例用到了一下的属性和方法:
         XmlDocument.Root:返回根节点(XmlNode 对象)
         XmlDocument.ToString:返回 Xml 的字符串

       XmlNode 有以下属性和方法在本例中使用:
         XmlNode.Props:返回一个属性集,后面可以直接加上 .<PropName> 或者 [<索引器>],可以为此属性取值赋值
         XmlNode.Nodes:返回一个节点集(XmlNodeList 对象)
         XmlNode.FindByProp(theName, theValue, [inSub]):返回一个子节点,最后一个可选参数规定是否深层次递归查找所有子节点

       本例用到了 XmlNodeList 的一个方法:
         XmNodeList.Add(theName, [theValue]):返回一个新子节点,最后一个可选参数指定其 Value

    2、本例中对于 ObjectSet 节点的创建调用了一个函数 FindOrCreateObjectSet,目的是对于相同的表名必须只能创建一次,从而将相同的表(TableRow,Object)放在同一个 ObjectSet 节点下。

【扩展】
    本例可以进一步扩展以增强其实用性,比如可以修改以用于更多类型的 XML 文档转换。
..>

本例运行结果如下:

<?xml version="1.0"?>
<ObjectSpace Name="Schema1">
  <ObjectSet Name="Table1">
    <Object Field11="A1" Field12="A2"/>
    <Object Field11="B1" Field12="B2"/>
    <Object Field11="C1" Field12="C2"/>
  </ObjectSet>
  <ObjectSet Name="Table2">
    <Object Field21="D1" Field22="D2" Field23="D3"/>
    <Object Field21="E1" Field22="E2" Field23="E3"/>
  </ObjectSet>
</ObjectSpace>