生成使用XMLWriter生成目标XML的PHP代码

本文关键字:代码 XML PHP XMLWriter 目标 | 更新日期: 2023-09-27 18:00:01

现在,使用XMLWriter从PHP创建XML文件并不困难,如下所示:

$objWriter->startDocument('1.0', 'UTF-8', 'yes');
// Data
$objWriter->startElement("Relationships");
$objWriter->writeAttribute("xmlns", "http://schemas.openxmlformats.org/package/2006/relationships");
$objWriter->startElement("Relationship");
$objWriter->writeAttribute("Id", "rId1");
$objWriter->writeAttribute("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartUserShapes");
$objWriter->writeAttribute("Target", "../drawings/drawing" . $drawingNum . ".xml");
$objWriter->endElement(); // Relationship
$objWriter->endElement(); // Relationships
$result = $objWriter->getData();

然而,如果我已经有了一个"模板"XML文件(比如说大约有30多行),我想通过这样的PHP生成它,其中很少有由PHP脚本计算的属性,该怎么办。

现在我可以去写startElementwriteAttributeendElement大约半个小时,或者我可以:

1) 自动生成这样的代码,使用一些解析XML(Java、C#、PHP等)的程序,读取标记和属性,并生成相应的PHP代码,这些代码反过来会生成原始XML。这会有很大帮助。

2) 只需用?>取消<?php标记并直接转储XML,只在需要的地方添加<?php echo $value ?>,然后使用一些技巧不将其写入stdout,而是将其存储在字符串中。如果这个技巧不涉及将其放入自己的脚本中并通过curl获得结果,那么这是可以接受的。

那么,你认为什么是最好的选择呢?我需要这个来用PHPExcel导出图表,我需要的很多东西都不受PHPExcel的支持,尤其是在图表领域,所以我只需要查看所需的XML文件并自己生成它们。

编辑:

这是我到目前为止在C#中代码生成的进展:

private static void doWork(string filename, Func<string, string> onElementStart, Func<string, string> onElementEnd, Func<string, string, string> onAttribute)
{
    using (XmlReader reader = XmlReader.Create("file:///" + filename))
    {
        using (StreamWriter file = new StreamWriter(@"c:'kajacx'other'troll_excel5'output.php"))
        {
            // Parse the file and display each of the nodes.
            while (reader.Read())
            {
                switch (reader.NodeType)
                {
                    case XmlNodeType.Element:
                        file.WriteLine(onElementStart(reader.Name));
                        break;
                    case XmlNodeType.Attribute:
                        file.WriteLine(onAttribute(reader.Name, reader.Value));
                        break;
                    case XmlNodeType.EndElement:
                        file.WriteLine(onElementEnd(reader.Name));
                        break;
                }
            }
        }
    }
}

工作得很好,只是它不解析属性(就像<tag attrName="attValue" />中一样,但总比什么都不解析好。有人知道如何使属性工作吗?

生成使用XMLWriter生成目标XML的PHP代码

与子元素不同,属性是在加载元素节点本身的同时加载的。因此,当使用reader.NodeType == XmlNodeType.Element时,可以使用XmlReader.MoveToNextAttribute()循环浏览属性,最后返回到具有XmlReader.MoveToElement():的元素

private static void DoWork(XmlReader reader, Action<string> onElementStart, Action<string> onElementEnd, Action<string, string> onAttribute)
{
    while (reader.Read())
    {
        switch (reader.NodeType)
        {
            case XmlNodeType.Element:
                onElementStart(reader.Name);
                if (reader.HasAttributes)
                {
                    while (reader.MoveToNextAttribute())
                    {
                        onAttribute(reader.Name, reader.Value);
                    }
                    // Move the reader back to the element node.
                    reader.MoveToElement();
                }
                if (reader.IsEmptyElement)
                {
                    // Do something special for empty elements?  
                }
                break;
            case XmlNodeType.Attribute:
                onAttribute(reader.Name, reader.Value);
                break;
            case XmlNodeType.EndElement:
                onElementEnd(reader.Name);
                break;
        }
    }
}
private static void doWork(string filename, Func<string, string> onElementStart, Func<string, string> onElementEnd, Func<string, string, string> onAttribute)
{
    using (XmlReader reader = XmlReader.Create("file:///" + filename))
    {
        using (StreamWriter writer = new StreamWriter(@"c:'kajacx'other'troll_excel5'output.php"))
        {
            DoWork(reader, writer, onElementEnd, onElementEnd, onAttribute);
        }
    }
}
private static void DoWork(XmlReader reader, TextWriter writer, Func<string, string> onElementStart, Func<string, string> onElementEnd, Func<string, string, string> onAttribute)
{
    DoWork(reader,
        (s) => writer.WriteLine(onElementStart(s)),
        (s) => writer.WriteLine(onElementEnd(s)),
        (s1, s2) => writer.WriteLine(onAttribute(s1, s2))
    );
}

(在这里,我重构了您的代码,使测试更容易。)