代码之家  ›  专栏  ›  技术社区  ›  Davide Gualano

在平面xml文件中创建结构

  •  1
  • Davide Gualano  · 技术社区  · 14 年前

    我有这样一个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 回复  |  直到 14 年前
        1
  •  1
  •   sargant    14 年前

    我不知道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();
    
      }
    }
    
        2
  •  8
  •   Tomalak    14 年前

    <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必须有一个 <color> 和一个 <speed> <car> . 如果不能保证,或者属性的数量和种类通常是可变的,请用copy语句的通用形式替换这两行:

    <!-- 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())
    ]" />
    

    <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的示例代码应该很容易找到,所以我在这里省略了它。它几乎不超过4到5行Python代码。

        3
  •  0
  •   John Machin Santi    14 年前

    如果 您的实际数据和您的示例一样简单,并且没有错误,您可以使用正则表达式替换一次性完成:

    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
    

        4
  •  0
  •   Steven    14 年前

    假设根中的第一个元素是 car 汽车 元素“属于”最后一个元素 汽车 :

    import xml.etree.cElementTree as etree
    
    root = etree.XML('''<root>
    <car>Ferrari</car>
    <color>red</color>
    <speed>300</speed>
    <car>Porsche</car>
    <color>black</color>
    <speed>310</speed>
    </root>''')
    
    new_root = etree.Element('root')
    
    for elem in root:
        if elem.tag == 'car':
            car = etree.SubElement(new_root, 'car', name=elem.text)
        else:
            car.append(elem)
    

    new_root

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

    (我认为漂亮的空白并不重要)