如何转换XML?

时间:2015-07-07 05:37:38

标签: xml xslt

我正在尝试构建一个组织结构图,我想我可能会尝试将我的数据转换为树状结构,如D3.js示例http://mbostock.github.io/d3/talk/20111018/tree.html

我有一个输入文件,它是从MS Access数据库中的查询生成的。 XML看起来像这样......

<?xml version="1.0" encoding="UTF-8"?>
<dataroot xmlns:od="urn:schemas-microsoft-com:officedata" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:noNamespaceSchemaLocation="Query1.xsd" generated="2015-06-25T15:35:33">
<Query1>
    <title>CEO</title>
    <reportsTo>1</reportsTo>
    <ID>1</ID>
</Query1>
<Query1>
    <title>Director of Operations</title>
    <reportsTo>1</reportsTo>
    <ID>2</ID>
</Query1>
<Query1>
    <title>Human Resources Manager</title>
    <reportsTo>2</reportsTo>
    <ID>3</ID>
</Query1>
</dataroot>

想要的输出看起来像这样...

<?xml version="1.0" encoding="UTF-8"?>
<employees>
<employee title="CEO" reportsTo="1" id="1">
    <employee title="Director of Operations" reportsTo="1" id="2">
        <employee title="Human Resources Manager" reportsTo="2" id="3"></employee>
    </employee>
</employee>
</employees>

这里重要的是员工之间的关系。我(想)我需要嵌套元素。 Access数据库的输出非常平坦,但它仍然具有员工ID号,以及与每个员工经理相对应的“reportsTo”号码。如果员工2向员工1报告,那么他们应该嵌套在员工1下面。(我已经为只报告自己的CEO提出了一个特例。)

一旦我得到这个结构,我应该很容易编写一个xslt来从我的输出XML转到D3.js的JS输入结构。看起来应该是这样......

var treeData = [
   {
    "name": "CEO",
    "parent": "null",
    "children": [
      {
        "name": "Director of Operations",
        "parent": "Top Level",
        "children": [
          {
            "name": "Human Resources Manager",
            "parent": "Level 2: A"
          }
       ]
      }
    ]
  }
];

目前,我编写了一个Python脚本来读取我的输入XML,我正在努力让它生成输出XML。

但我觉得我错过了一些东西。我可以写一个xslt直接从输入xml到输出xml文件吗?或者甚至直接从输入xml文件直接到JS输出?

也许我在“代码”解决方案方面一直在考虑太多。如何在不使用我的python脚本的情况下在xslt中执行此操作?

1 个答案:

答案 0 :(得分:1)

首先让我们忽略循环问题,让我们假设我们知道组织树的根是$ boss(它可能是第一个雇员,或ID = 1的那个,或者reportTo = ID的那个)。

定义一个键

<xsl:key name="k" match="Query1" use="reportsTo"/>

模板规则:

<xsl:template match="Query1">
  <employee title="{title}" reportsTo="{reportsTo}" ID="{ID}">
    <xsl:apply-templates select="key('k', ID)"/>
  </employee>
</xsl:template>

现在你可以用

来解决问题了
<xsl:apply-templates select="$boss"/>

唯一剩下的问题是,如果您的数据中有周期,则会无限期地递归。您的数据确实有一个周期:首席执行官向自己报告。也可能有其他周期。您可以将CEO作为一个特例处理,或者您可以添加逻辑来检测一般情况下的周期;这基本上是通过将参数传递给给出祖先员工列表的模板来完成的。但是在这个阶段,使用XSLT 2.0比使用1.0开始变得容易得多,而你还没有说出你使用的是什么。