在平面XML文件中创建结构

1 投票
4 回答
930 浏览
提问于 2025-04-16 00:50

我有一个这样的xml文件:

<car>Ferrari</car>
<color>red</color>
<speed>300</speed>
<car>Porsche</car>
<color>black</color>
<speed>310</speed>

我需要把它变成这个样子:

<car name="Ferrari">
    <color>red</color>
    <speed>300</speed>
</car>
<car name="Porsche">
    <color>black</color>
    <speed>310</speed>
</car>

我该怎么做呢?我遇到困难了,因为我想不到如何从原始xml文件中平坦的标签列表创建我需要的结构。

我选择的编程语言是Python,但任何建议我都欢迎。

4 个回答

0

如果你的实际数据和你的例子一样简单,而且没有任何错误,你可以用正则表达式替换一次性搞定:

import re

guff = """
<car>Ferrari</car>
<color>red</color>
<speed>300</speed>
<car>Porsche</car>
<color>black</color>
<speed>310</speed>
"""

pattern = r"""
<car>([^<]+)</car>\s*
<color>([^<]+)</color>\s*
<speed>([^<]+)</speed>\s*
"""

repl = r"""<car name="\1">
    <color>\2</color>
    <speed>\3</speed>
</car>
"""

regex = re.compile(pattern, re.VERBOSE)
output = regex.sub(repl, guff)
print output

否则,你最好每次读取三行数据,进行一些验证,然后一个一个地写出“车”元素,可以使用字符串处理或者ElementTree来完成。

8

XSLT 是一个非常适合把一种 XML 结构转换成另一种的工具。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <!-- copy the root element and handle its <car> children -->
  <xsl:template match="/root">
    <xsl:copy>
      <xsl:apply-templates select="car" />
    <xsl:copy>
  </xsl:template>

  <!-- car elements become a container for their properties -->
  <xsl:template match="car">
    <car name="{normalize-space()}">
      <!-- ** see 1) -->
      <xsl:copy-of select="following-sibling::color[1]" />
      <xsl:copy-of select="following-sibling::speed[1]" />
    </car>
  </xsl:template>
</xsl:stylesheet>

1) 要让这个转换顺利进行,你的 XML 里每个 <car> 都必须有 <color><speed> 这两个部分。如果这两个部分不一定存在,或者属性的数量和种类可能会变化,那就把这两行代码换成更通用的复制语句:

<!-- any following-sibling element that "belongs" to the same <car> -->
<xsl:copy-of select="following-sibling::*[
  generate-id(preceding-sibling::car[1]) = generate-id(current())
]" />

如果应用到你的 XML(我假设有一个名为 <root> 的根元素),那么结果就是这样:

<root>
  <car name="Ferrari">
    <color>red</color>
    <speed>300</speed>
  </car>
  <car name="Porsche">
    <color>black</color>
    <speed>310</speed>
  </car>
</root>

在 Python 中应用 XSLT 到 XML 的示例代码其实很容易找到,所以我这里就不写了。通常也就四五行 Python 代码而已。

1

我对Python不太了解,不过假设你有一个可以解析XML的工具,它能让你以层级的方式访问XML文档中的节点。你想要的逻辑大概是这样的(警告,我通常用PHP)。基本上,你需要存储任何不是“car”的标签,然后当你遇到一个新的“car”标签时,把它当作一个分隔符,创建一个组合好的XML节点:

// Create an input and output handle
input_handle = parse_xml_document();
output_handle = new_xml_document();

// Assuming the <car>, <color> etc. nodes are
// the children of some, get them as an array
list_of_nodes = input_handle.get_list_child_nodes();

// These are empty variables for storing our data as we parse it
var car, color, speed = NULL

foreach(list_of_nodes as node)
{
  if(node.tag_name() == "speed")
  {
    speed = node.value();
    // etc for each type of non-delimiting field          
  }

  if(node.tag_name() == "car")
  {
    // If there's already a car specified, take its data,
    // insert it into the output xml structure and th
    if(car != NULL)
    {
      // Add a new child node to the output document
      node = output_handle.append_child_node("car");
      // Set the attribute on this new output node
      node.set_attribute("name", node.value());
      // Add the stored child attributes
      node.add_child("color", color);
      node.add_child("speed", speed);
    }

    // Replace the value of car afterwards. This allows the
    // first iteration to happen when there is no stored value
    // for "car".
    car = node.value();

  }
}

撰写回答