• 解决创建带有NameSpace的XML文件出现空白xmlns的问题


    为了能够让用户自行部署ClickOnce应用程序,需要编写一个生成ClickOnce应用程序的ClickOnce专用安装程序setup.exe,而生成这个setup.exe的方法就是编写一个XML格式的生成配置文件,使用MSBuild.exe来创建。
      一般情况下,创建XML文件本来是个很简单的事情,用XDocument、XElement、XAttribute一顿Add,然后Save成文件就完成了。但是创建setup.exe用的XML文件的根节点(Project)必须指定XML名称空间"http://schemas.microsoft.com/developer/msbuild/2003",形式如下:

    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
        <ItemGroup>
                <BootstrapperFile Include=".NETFramework,Version=v4.0">
                  <ProductName>Microsoft .NET Framework 4 (x86 和 x64)</ProductName>
                </BootstrapperFile>
                <BootstrapperFile Include="Microsoft.Windows.Installer.3.1">
                  <ProductName>Windows Installer 3.1</ProductName>
                </BootstrapperFile>
        </ItemGroup>
    
        <Target Name="BuildBootstrapper">
            <GenerateBootstrapper
                ApplicationFile="MyApp.application"
                ApplicationName="我的应用程序"
                ApplicationUrl="http://192.168.0.8/MyApp/"
                BootstrapperItems="@(BootstrapperFile)"
                CopyComponents="false"
                OutputPath="."
                Path="X:SerupExeBuilderPackages"/>
        </Target>
    </Project>

    于是,生成该XML的代码则写为:

    #region ItemGroup
    XElement itemGroup = new XElement("ItemGroup",
        new XElement("BootstrapperFile",
            new XAttribute("Include", ".NETFramework,Version=v4.0"),
            new XElement("ProductName", "Microsoft .NET Framework 4 (x86 和 x64%)")),
        new XElement("BootstrapperFile",
            new XAttribute("Include", "Microsoft.Windows.Installer.3.1"),
            new XElement("ProductName", "Windows Installer 3.1"))
            );
    #endregion
    
    #region Target
    XElement target = new XElement("Target");
    target.Add(new XAttribute("Name", "BuildBootstrapper"));
    XElement generateBootstrapper = new XElement("GenerateBootstrapper");
    generateBootstrapper.Add(new XAttribute("ApplicationFile", applicationFile));
    generateBootstrapper.Add(new XAttribute("ApplicationName", applicationName));
    generateBootstrapper.Add(new XAttribute("ApplicationUrl", applicationUrl));
    
    if (componentsLocation == 1)
    {
        generateBootstrapper.Add(new XAttribute("ComponentsLocation", "Relative"));
    }
    else if (componentsLocation == 2 && !string.IsNullOrWhiteSpace(componentsUrl))
    {
        generateBootstrapper.Add(new XAttribute("ComponentsLocation", "Absolute"));
        generateBootstrapper.Add(new XAttribute("ComponentsUrl", componentsUrl));
    }
    
    generateBootstrapper.Add(new XAttribute("BootstrapperItems", "@(BootstrapperFile)"));
    generateBootstrapper.Add(new XAttribute("CopyComponents", false));
    generateBootstrapper.Add(new XAttribute("OutputPath", outputPath));
    string packagesPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
    generateBootstrapper.Add(new XAttribute("Path", Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)));
    target.Add(generateBootstrapper);
    #endregion
    
    XNamespace xmlns = "http://schemas.microsoft.com/developer/msbuild/2003";
    XElement root = new XElement(xmlns + "Project");
    
    root.Add(itemGroup);
    root.Add(target);
    
    XDocument setupDocument = new XDocument();
    setupDocument.Add(root);
    
    setupDocument.Declaration = new XDeclaration("1.0", "UTF-8", "yes");
    setupDocument.Save(Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "setup.xml"));

    但是生成的XML文件中,ItemGroup和Target节点上会出现 xmlns="" 的属性,而这在编译的时候是不允许的(也是错误的),而又没有办法不让它们出现。

    这个问题郁闷了一阵子,也没找到资料,最后用土办法,也就是StringBuilder手工创建,程序是成功了,但是这个问题一直耿耿于怀。

    今天终于知道原因了,当然也知道了“解决办法”了。
    其实原因是,在XML中,如果某个节点使用了NameSpace,则要求其下的每个节点都必须指定NameSpace的,以便于区分各个节点属于哪一个NameSpace。在生成XML文件的时候,如果子节点的NameSpace与父节点相同,则忽略xmlns属性。所以在创建子节点的时候,必须为子节点指定NameSpace,否则就会因为没有指定NameSpace,出现 xmlns="" 的情况。
    所以是对XML的NameSpace了解的不够,才导致程序的错误写法。因此,改为正确的写法,问题自然就消失不见了。当然,这个实际上不能称为“解决办法” 。
             

    另外,该setup.exe也可以使用Microsoft.Build.Tasks.GenerateBootstrapper生成,但是目前只做到生成,尚未进行实践验证。

  • 相关阅读:
    AcWing 838. 堆排序
    AcWing 240. 食物链
    Sublime下载地址
    【转载】Java 8 Optional的正确姿势
    【SpringBoot】通过server.servlet.context-path设置应用的上下文路径
    【java/Lamda】List.stream().collect(Collectors.toMap(Emp::getId, a->a,(k1,k2)->k2))的意义
    Prometheus修改数据保留时间
    Atitit BLE 协议栈 艾提拉总结 目录 1. ——关于BLE的一些基本概念——
    Atitit 高并发设计实践 艾提拉著 目录 1. 并发的实现俩中模式 并发角度来看 基于事件触发vs线程的 1 2. 负载均衡 1 2.1. 云服务模型paas caas faas+http
    Atitit 锁的不同层级 app锁 vm锁 os锁 硬件锁 目录 1. 在硬件层面,CPU提供了原子操作、关中断、锁内存总线的机制 1 1.1. test and set指令 1 1.2. 锁内
  • 原文地址:https://www.cnblogs.com/yuxs/p/3177783.html
Copyright © 2020-2023  润新知