You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#生成XML时如何避免添加无Url的Photo节点

问题:LINQ to XML生成产品XML时过滤空Photo节点

我使用C#的LINQ to XML从DataTable生成产品XML,当前代码会在Photos节点下生成不含Url子节点的空Photo元素,示例如下:

<Photos>
    <Photo>
        <Url>https://some.pl/Url>
        <IsPrimary>true</IsPrimary>
    </Photo>
    <Photo>
        <IsPrimary>false</IsPrimary>
    </Photo>
    <Photo>
        <IsPrimary>false</IsPrimary>
    </Photo>
    <!-- 更多空Photo节点 -->
</Photos>

我需要只保留包含有效Url的Photo元素,期望输出:

<Photos>
    <Photo>
        <Url>https://some.pl/Url>
        <IsPrimary>true</IsPrimary>
    </Photo>
    <Photo>
        <Url>https://some.pl</Url>
        <IsPrimary>false</IsPrimary>
    </Photo>
</Photos>

原生成代码如下:

//// Group the rows by Department (all 123A in your question).
var departments = dt.AsEnumerable().GroupBy(r => r.Field<string>("ID"));

// Generate the root element
var root = new XElement("Catalog",
    departments.Select(
        d =>
        new XElement("Product",
            new XElement("Id", d.Key),
            d.Select(r => new XElement("LastMod", r.Field<string>("Update_date"))),
            d.Select(r => new XElement("StructuredId", r.Field<string>("EAN"))),
            new XElement("Descriptions",
                d.Select(r => new XElement("Name", r.Field<string>("Name"))),
                d.Select(r => new XElement("Description", r.Field<string>("Description")))
                ),
            new XElement("Prices",
                d.Select(r => new XElement("Currency", "EUR")),
                d.Select(r => new XElement("Price", r.Field<double>("Price_netto_EUR")))
                ),
            new XElement("Warranty",
                d.Select(r => new XElement("Type", "Year")),
                d.Select(r => new XElement("Duration", r.Field<string>("Guarantee").Replace(" years", "")))
                ),
             new XElement("Categories",
             new XElement("Category",
             d.Select(r => new XElement("Name", r.Field<string>("Category")))
            )),
             new XElement("Photos",
             new XElement("Photo", 
             d.Select(r => new XElement("Url", r.Field<string>("ImageURL1"))),
             new XElement("IsPrimary", "true") 
             ),
             new XElement("Photo", 
             d.Select(r => new XElement("Url", r.Field<string>("ImageURL2"))),
             new XElement("IsPrimary", "false")
             ),
                new XElement("Photo",
             d.Select(r => new XElement("Url", r.Field<string>("ImageURL3"))),
             d.Select(r => new XElement("IsPrimary", "false"))
             ),
             new XElement("Photo",
             d.Select(r => new XElement("Url", r.Field<string>("ImageURL4"))),
             d.Select(r => new XElement("IsPrimary", "false"))
             ),
               new XElement("Photo",
             d.Select(r => new XElement("Url", r.Field<string>("ImageURL5"))),
             d.Select(r => new XElement("IsPrimary", "false"))
             ),
             new XElement("Photo",
             d.Select(r => new XElement("Url", r.Field<string>("FileURL1"))),
             d.Select(r => new XElement("IsPrimary", "false"))
             ),
             new XElement("Photo",
             d.Select(r => new XElement("Url", r.Field<string>("FileURL2"))),
             d.Select(r => new XElement("IsPrimary", "false"))
             ),
             new XElement("Photo",
             d.Select(r => new XElement("Url", r.Field<string>("FileURL3"))),
             d.Select(r => new XElement("IsPrimary", "false"))
             ),
             new XElement("Photo",
             d.Select(r => new XElement("Url", r.Field<string>("FileURL4"))),
             d.Select(r => new XElement("IsPrimary", "false"))
             ),
             new XElement("Photo",
             d.Select(r => new XElement("Url", r.Field<string>("FileURL5"))),
             d.Select(r => new XElement("IsPrimary", "false"))
             )
             ),
             new XElement("Availability",
             d.Select(r => new XElement("Available", r.Field<string>("Available"))),
             d.Select(r => new XElement("Quantity", r.Field<string>("STOCK"))),
             d.Select(r => new XElement("ShippingDelay", r.Field<string>("LEADTIME_DAYS")))
            ),
             new XElement("Attributes",
                 new XElement("Attribute", 
                 d.Select(r => new XElement("AttributeName", "Style")),
                 d.Select(r => new XElement("AttributeValue", r.Field<string>("Style")))
                 ),
                 new XElement("Attribute",
                 d.Select(r => new XElement("AttributeName", "PrimaryColor")),
                 d.Select(r => new XElement("AttributeValue", r.Field<string>("Primary_color")))
                 ),
                 new XElement("Attribute",
                 d.Select(r => new XElement("AttributeName", "UpholysteryMaterial")),
                 d.Select(r => new XElement("AttributeValue", r.Field<string>("UpholysteryMaterial")))
                 ),
                 new XElement("Attribute",
                 d.Select(r => new XElement("AttributeName", "WeightCapacity")),
                 d.Select(r => new XElement("AttributeValue", r.Field<string>("Weight_capacity")))
                 ),
                 new XElement("Attribute",
                 d.Select(r => new XElement("AttributeName", "SeatAreaWidth")),
                 d.Select(r => new XElement("AttributeValue", r.Field<string>("SeatAreaWidth")))
                 ),
                 new XElement("Attribute",
                 d.Select(r => new XElement("AttributeName", "SeatAreaDepth")),
                 d.Select(r => new XElement("AttributeValue", r.Field<string>("SeatAreaDepth")))
                 ),
                 new XElement("Attribute",
                 d.Select(r => new XElement("AttributeName", "SeatCapacity")),
                 d.Select(r => new XElement("AttributeValue", r.Field<string>("SeatCapacity")))
                 ),
                 new XElement("Attribute",
                 d.Select(r => new XElement("AttributeName", "SleepFunction")),
                 d.Select(r => new XElement("AttributeValue", r.Field<string>("SleepFunction")))
                 ),
                 new XElement("Attribute",
                 d.Select(r => new XElement("AttributeName", "PackagesNumbers")),
                 d.Select(r => new XElement("AttributeValue", r.Field<double>("Packages_Numbers")))
                 ),
                 new XElement("Attribute",
                 d.Select(r => new XElement("AttributeName", "TotalWeight")),
                 d.Select(r => new XElement("AttributeValue", r.Field<string>("Total_Weight")))
                 ),
                 new XElement("Attribute",
                 d.Select(r => new XElement("AttributeName", "AdultAssemblyRequired")),
                 d.Select(r => new XElement("AttributeValue", r.Field<string>("AdultAssemblyRequired")))
                 ),
                 new XElement("Attribute",
                 d.Select(r => new XElement("AttributeName", "AssemblyLevel")),
                 d.Select(r => new XElement("AttributeValue", r.Field<string>("Assembly_Level")))
                 ),
                 new XElement("Attribute",
                 d.Select(r => new XElement("AttributeName", "Backtype")),
                 d.Select(r => new XElement("AttributeValue", r.Field<string>("Backtype")))
                 ),
                 new XElement("Attribute",
                 d.Select(r => new XElement("AttributeName", "FrameMaterial")),
                 d.Select(r => new XElement("AttributeValue", r.Field<string>("FrameMaterial")))
                 ),
                 new XElement("Attribute",
                 d.Select(r => new XElement("AttributeName", "Framewoodtype")),
                 d.Select(r => new XElement("AttributeValue", r.Field<string>("Framewoodtype")))
                 )
             ),
             new XElement("VolumeDimensions",
             d.Select(r => new XElement("Width", r.Field<string>("Width"))),
             d.Select(r => new XElement("Height", r.Field<string>("Height"))),
             d.Select(r => new XElement("Length", r.Field<string>("Length"))),
             d.Select(r => new XElement("Depth", r.Field<string>("Depth")))
            )
        )
    )
);

解决方案:过滤空URL的Photo节点

问题根源是原代码逐个创建Photo元素,不管对应URL字段是否为空。修改思路是:先定义所有图片URL字段及其对应的IsPrimary状态,过滤掉空URL的项后再生成Photo元素。

修改后的Photos节点代码如下:

new XElement("Photos",
    // 定义所有图片URL字段和对应的IsPrimary状态
    new List<(string FieldName, bool IsPrimary)>
    {
        ("ImageURL1", true),
        ("ImageURL2", false),
        ("ImageURL3", false),
        ("ImageURL4", false),
        ("ImageURL5", false),
        ("FileURL1", false),
        ("FileURL2", false),
        ("FileURL3", false),
        ("FileURL4", false),
        ("FileURL5", false)
    }
    .Select(field => 
    {
        // 分组后同一ID的行字段值一致,取第一个行的字段值
        var url = d.First().Field<string>(field.FieldName);
        // 过滤空URL
        if (string.IsNullOrWhiteSpace(url)) return null;
        return new XElement("Photo",
            new XElement("Url", url),
            new XElement("IsPrimary", field.IsPrimary.ToString().ToLower())
        );
    })
    // 移除null项,避免生成空Photo元素
    .Where(photo => photo != null)
)

关键说明

  1. 用元组列表统一管理所有图片字段和IsPrimary状态,代码更简洁易维护。
  2. 分组后同一ID的行数据一致,直接取First()获取URL值即可,无需遍历整组。
  3. 通过string.IsNullOrWhiteSpace判断URL有效性,为空则返回null。
  4. 最后用Where(photo => photo != null)过滤掉空项,确保只生成含有效URL的Photo元素。

完整修改后的代码只需要替换原代码中Photos节点的部分即可。

内容的提问来源于stack exchange,提问作者RemuRemue

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 16:38:08