如何在 xml 文件中使用 ruby 创建树结构生成器?

how to create a tree structure generator with ruby in a xml file?

我在一个项目中,我必须从 Ubuntu 为 Windows 创建一个 msi 包。

我设法创建了一个从 Ubuntu rgace 到“msitools”的 msi 文件,它使用 wxs 文件(类似于 xml 文件)来配置程序包。

一个 wxs 文件的示例,它占用一个文件 (FoobarAppl10.exe)。

<?xml version='1.0' encoding='windows-1252'?>
<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>
  <Product Name='Foobar 1.0' Id='ABCDDCBA-86C7-4D14-AEC0-86416A69ABDE' UpgradeCode='ABCDDCBA-7349-453F-94F6-BCB5110BA4FD'
    Language='1033' Codepage='1252' Version='1.0.0' Manufacturer='Acme Ltd.'>

<Package Id='*' Keywords='Installer' Description="Acme's Foobar 1.0 Installer"
  Comments='Foobar is a registered trademark of Acme Ltd.' Manufacturer='Acme Ltd.'
  InstallerVersion='100' Languages='1033' Compressed='yes' SummaryCodepage='1252' />

<Media Id='1' Cabinet='Sample.cab' EmbedCab='yes' DiskPrompt="CD-ROM #1" />
<Property Id='DiskPrompt' Value="Acme's Foobar 1.0 Installation [1]" />

<Directory Id='TARGETDIR' Name='SourceDir'>
  <Directory Id='ProgramFilesFolder' Name='PFiles'>
    <Directory Id='Acme' Name='Acme'>
      <Directory Id='INSTALLDIR' Name='Foobar 1.0'>

        <Component Id='MainExecutable' Guid='ABCDDCBA-83F1-4F22-985B-FDB3C8ABD471'>
          <File Id='FoobarEXE' Name='FoobarAppl10.exe' DiskId='1' Source='FoobarAppl10.exe' KeyPath='yes'/>
        </Component>

      </Directory>
    </Directory>
  </Directory>
</Directory>

<Feature Id='Complete' Level='1'>
  <ComponentRef Id='MainExecutable' />
</Feature>
</Product>
</Wix>

现在我的问题是用ruby创建一个树结构生成器,这样我的wxs文件就可以打包我项目的所有文件而无需手动编写。

我写了一个代码,可以创建一个 xml 文件,并在其中打印我的暴力代码:

$ ls

build.wxs foobarAppl10.exe generator_xml.rb

require 'nokogiri'

out_file = File.new("generated.wxs", "w")

builder = Nokogiri::XML::Builder.new(:encoding => 'windows-1252') { |xml|
  xml.Wix('xmlns' => 'http://schemas.microsoft.com/wix/2006/wi') do
    xml.Product('Name' => 'Foobar 1.0', 'Id' => 'ABCDDCBA-86C7-4D14-AEC0-86416A69ABDE',
    'UpgradeCode' =>'ABCDDCBA-7349-453F-94F6-BCB5110BA4FD',  'Language' => '1033', 'Codepage' => '1252',
    'Version' => '1.0.0', 'Manufacturer' => 'Acme Ltd.') do
      
      xml.Package('Id' => '*', 'Keywords' => 'Installer', 'Description' => "Acme's Foobar 1.0 Installer", 
      'Comments' => 'Foobar is a registered trademark of Acme Ltd.', 'Manufacturer' => 'Acme Ltd.',
      'InstallerVersion' => '100', 'Languages' => '1033', 'Compressed' => 'yes', 'SummaryCodepage' => '1252')
    
      xml.Media('Id' => '1', 'Cabinet' => 'Sample.cab', 'EmbedCab' => 'yes', 'DiskPrompt' => "CD-ROM #1")
    
      xml.Property('Id' => 'DiskPromt', 'Value' => "Acme's Foobar 1.0 Installation [1]")

      xml.Directory('Id' => 'TARGETDIR', 'Name' =>'SourceDir') do
        xml.Directory('Id' => 'ProgramFilesFolder', 'Name' =>'PFiles') do
          xml.Directory('Id' => 'Acme', 'Name' =>'Acme') do
            xml.Directory('Id' => 'INSTALLDIR', 'Name' =>'Foobar 1.0') do

              xml.Component('Id' => 'MainExecutable', 'Guid' => 'ABCDDCBA-83F1-4F22-985B-FDB3C8ABD471') do
            
                xml.File('Id' => 'FoobarEXE', 'Name' => 'FoobarAppl10.exe', 'DiskId' => '1', 'Source' => 'FoobarAppl10.exe', 'KeyPath' =>'yes')
            
              end

            end
          end
        end
      end
      xml.Feature('Id' => 'Complete', 'Level' => '1') do
        xml.Component('Id' => 'MainExecutable')
      end
    end
  end
}

puts builder.to_xml

out_file.puts(builder.to_xml)
out_file.close

如果有人知道如何从树结构生成代码,那将对我有很大帮助!

听起来您想要创建一个模仿目录结构的 XML 结构?这是一个递归函数,它应该可以完成您想要的大部分工作,或者至少可以作为一个很好的起点。 puts 语句可以删除或替换为您在查找目录或文件时需要执行的任何其他操作。

require 'nokogiri'

def process_dir(current_path, xml)
    return if !File.directory?(current_path) || Dir.empty?(current_path)
    directory_name = current_path.split("/").last
    # insert code here to compute other attributes for Directory node
    xml.Directory(Name: directory_name) do
        Dir.children(current_path).each do |entry| 
            file = "#{current_path}/#{entry}"
            if !File.directory?(file)
                # insert code here to compute other attributes for File node
                xml.File(Name: entry)
                puts "found file named #{entry} at #{current_path}"
            else
                puts "found directory named #{current_path}/#{entry}"
                process_dir("#{current_path}/#{entry}", xml)
            end
        end
    end
end

builder = Nokogiri::XML::Builder.new do |xml|
    xml.root { process_dir(".", xml) }
end

pp builder.to_xml