使用 C# 批量编辑 XML 中的特定元素
Bulk Editing Specific Elements in an XML with C#
我有一个 .xml 文件,它在两个不同元素之间共享一个属性。我正在尝试将一个元素中的属性乘以一个变量,并将另一个元素中的属性乘以另一个变量。
<acquirecosts>
<item>
<key>COST_SHOP_DEFAULT</key>
<quantity value="1"/>
<costtype>COST_TYPE_PRICE</costtype>
<items>
<item>
<item>CURRENCY_CASH</item>
<quantity value="6000"/>
</item>
</items>
<unlocks/>
</item>
</acquirecosts>
<sellprices>
<item>
<key>SELL_SHOP_DEFAULT</key>
<quantity value="1"/>
<costtype>COST_TYPE_PRICE</costtype>
<items>
<item>
<item>CURRENCY_CASH</item>
<quantity value="6000"/>
</item>
</items>
<unlocks/>
</item>
</sellprices>
<./acquirecosts> 中的“CURRENCY_CASH”数量值乘以 2,<./sellprices> 中的“CURRENCY_CASH”数量值乘以 0.5。
using System;
using System.Xml;
using System.Xml.XPath;
XmlDocument doc = new XmlDocument();
doc.Load(@"C:\Users\Darkye\Desktop\shopprices.xml");
var buyModifier = 2;
var sellModifier = 0.5;
var caItNodesBuy = caNode.XPathSelectElement("./acquirecosts").Elements();
foreach (var caItNodeBuy in caItNodesBuy)
{
var caItNodeItems = caItNodeBuy.XPathSelectElement("./items").Elements();
foreach (var item in caItNodeItems)
{
var caItNodeItemKey = item.Element("item").Value;
if (caItNodeItemKey != "CURRENCY_CASH") continue;
var caItNodeItemValue = (int)Math.Floor((double)int.Parse(item.Element("quantity").Attribute("value").Value) * buyModifier);
item.Element("quantity").SetAttributeValue("value", caItNodeItemValue);
}
caItNodeBuy.XPathSelectElement("./items").ReplaceNodes(caItNodeItems);
}
caNode.XPathSelectElement("./acquirecosts").ReplaceNodes(caItNodesBuy);
var caItNodesSell = caNode.XPathSelectElement("./sellprices").Elements();
foreach (var caItNodeSell in caItNodesSell)
{
var caItNodeItems = caItNodeSell.XPathSelectElement("./items").Elements();
foreach (var item in caItNodeItems)
{
var caItNodeItemKey = item.Element("item").Value;
if (caItNodeItemKey != "CURRENCY_CASH") continue;
var caItNodeItemValue = (int)Math.Floor((double)int.Parse(item.Element("quantity").Attribute("value").Value) * sellModifier);
item.Element("quantity").SetAttributeValue("value", caItNodeItemValue);
}
caItNodeSell.XPathSelectElement("./items").ReplaceNodes(caItNodeItems);
}
caNode.XPathSelectElement("./sellprices").ReplaceNodes(caItNodesSell);
但我正在努力弄清楚将“caNode”引入什么以及在哪里引入。我假设它是一个变量,但我迷失了。将 caNode 更改为“doc”时,它只会在 XPathSelectElement 上引入错误。除非有更简单的方法在特定元素中应用这些编辑,否则我不确定还能尝试什么。
请尝试以下解决方案。
它正在使用所谓的身份转换模式。
它将根据所需逻辑修改 <quantity>
元素 @value
属性值,而不触及任何其他内容。
输入XML
<root>
<acquirecosts>
<item>
<key>COST_SHOP_DEFAULT</key>
<quantity value="1"/>
<costtype>COST_TYPE_PRICE</costtype>
<items>
<item>
<item>CURRENCY_CASH</item>
<quantity value="6000"/>
</item>
</items>
<unlocks/>
</item>
</acquirecosts>
<sellprices>
<item>
<key>SELL_SHOP_DEFAULT</key>
<quantity value="1"/>
<costtype>COST_TYPE_PRICE</costtype>
<items>
<item>
<item>CURRENCY_CASH</item>
<quantity value="6000"/>
</item>
</items>
<unlocks/>
</item>
</sellprices>
</root>
XSLT
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="quantity">
<xsl:choose>
<xsl:when test="preceding-sibling::*='CURRENCY_CASH'">
<xsl:copy>
<xsl:attribute name="value">
<xsl:if test="ancestor::*[local-name() = 'acquirecosts']">
<xsl:value-of select="@value * 2"/>
</xsl:if>
<xsl:if test="ancestor::*[local-name() = 'sellprices']">
<xsl:value-of select="@value * 0.5"/>
</xsl:if>
</xsl:attribute>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
输出XML
<root>
<acquirecosts>
<item>
<key>COST_SHOP_DEFAULT</key>
<quantity value="1" />
<costtype>COST_TYPE_PRICE</costtype>
<items>
<item>
<item>CURRENCY_CASH</item>
<quantity value="12000" />
</item>
</items>
<unlocks />
</item>
</acquirecosts>
<sellprices>
<item>
<key>SELL_SHOP_DEFAULT</key>
<quantity value="1" />
<costtype>COST_TYPE_PRICE</costtype>
<items>
<item>
<item>CURRENCY_CASH</item>
<quantity value="3000" />
</item>
</items>
<unlocks />
</item>
</sellprices>
</root>
c#,XSLT 转换
void Main()
{
const string SOURCEXMLFILE = @"e:\Temp\input.xml";
const string XSLTFILE = @"e:\Temp\process.xslt";
const string OUTPUTXMLFILE = @"e:\temp\output.xml";
try
{
XsltArgumentList xslArg = new XsltArgumentList();
using (XmlReader src = XmlReader.Create(SOURCEXMLFILE))
{
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(XSLTFILE, new XsltSettings(true, true), new XmlUrlResolver());
XmlWriterSettings settings = xslt.OutputSettings.Clone();
settings.IndentChars = "\t";
// to remove BOM
settings.Encoding = new UTF8Encoding(false);
using (XmlWriter result = XmlWriter.Create(OUTPUTXMLFILE, settings))
{
xslt.Transform(src, xslArg, result, new XmlUrlResolver());
result.Close();
}
}
Console.WriteLine("File '{0}' has been generated.", OUTPUTXMLFILE);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
使用 Xml Linq 并进行两次传递
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XElement acquiredcosts = doc.Descendants("acquirecosts").FirstOrDefault();
List<XElement> currentCash = acquiredcosts.Descendants("item").Where(x => (string)x.Element("item") == "CURRENCY_CASH").ToList();
foreach (XElement c in currentCash)
{
XElement quantity = c.Element("quantity");
quantity.SetAttributeValue("value", 2 * (int)quantity.Attribute("value"));
}
XElement sellPrices = doc.Descendants("sellprices").FirstOrDefault();
currentCash = sellPrices.Descendants("item").Where(x => (string)x.Element("item") == "CURRENCY_CASH").ToList();
foreach (XElement c in currentCash)
{
XElement quantity = c.Element("quantity");
quantity.SetAttributeValue("value", .5 * (int)quantity.Attribute("value"));
}
}
}
}
我有一个 .xml 文件,它在两个不同元素之间共享一个属性。我正在尝试将一个元素中的属性乘以一个变量,并将另一个元素中的属性乘以另一个变量。
<acquirecosts>
<item>
<key>COST_SHOP_DEFAULT</key>
<quantity value="1"/>
<costtype>COST_TYPE_PRICE</costtype>
<items>
<item>
<item>CURRENCY_CASH</item>
<quantity value="6000"/>
</item>
</items>
<unlocks/>
</item>
</acquirecosts>
<sellprices>
<item>
<key>SELL_SHOP_DEFAULT</key>
<quantity value="1"/>
<costtype>COST_TYPE_PRICE</costtype>
<items>
<item>
<item>CURRENCY_CASH</item>
<quantity value="6000"/>
</item>
</items>
<unlocks/>
</item>
</sellprices>
<./acquirecosts> 中的“CURRENCY_CASH”数量值乘以 2,<./sellprices> 中的“CURRENCY_CASH”数量值乘以 0.5。
using System;
using System.Xml;
using System.Xml.XPath;
XmlDocument doc = new XmlDocument();
doc.Load(@"C:\Users\Darkye\Desktop\shopprices.xml");
var buyModifier = 2;
var sellModifier = 0.5;
var caItNodesBuy = caNode.XPathSelectElement("./acquirecosts").Elements();
foreach (var caItNodeBuy in caItNodesBuy)
{
var caItNodeItems = caItNodeBuy.XPathSelectElement("./items").Elements();
foreach (var item in caItNodeItems)
{
var caItNodeItemKey = item.Element("item").Value;
if (caItNodeItemKey != "CURRENCY_CASH") continue;
var caItNodeItemValue = (int)Math.Floor((double)int.Parse(item.Element("quantity").Attribute("value").Value) * buyModifier);
item.Element("quantity").SetAttributeValue("value", caItNodeItemValue);
}
caItNodeBuy.XPathSelectElement("./items").ReplaceNodes(caItNodeItems);
}
caNode.XPathSelectElement("./acquirecosts").ReplaceNodes(caItNodesBuy);
var caItNodesSell = caNode.XPathSelectElement("./sellprices").Elements();
foreach (var caItNodeSell in caItNodesSell)
{
var caItNodeItems = caItNodeSell.XPathSelectElement("./items").Elements();
foreach (var item in caItNodeItems)
{
var caItNodeItemKey = item.Element("item").Value;
if (caItNodeItemKey != "CURRENCY_CASH") continue;
var caItNodeItemValue = (int)Math.Floor((double)int.Parse(item.Element("quantity").Attribute("value").Value) * sellModifier);
item.Element("quantity").SetAttributeValue("value", caItNodeItemValue);
}
caItNodeSell.XPathSelectElement("./items").ReplaceNodes(caItNodeItems);
}
caNode.XPathSelectElement("./sellprices").ReplaceNodes(caItNodesSell);
但我正在努力弄清楚将“caNode”引入什么以及在哪里引入。我假设它是一个变量,但我迷失了。将 caNode 更改为“doc”时,它只会在 XPathSelectElement 上引入错误。除非有更简单的方法在特定元素中应用这些编辑,否则我不确定还能尝试什么。
请尝试以下解决方案。
它正在使用所谓的身份转换模式。
它将根据所需逻辑修改 <quantity>
元素 @value
属性值,而不触及任何其他内容。
输入XML
<root>
<acquirecosts>
<item>
<key>COST_SHOP_DEFAULT</key>
<quantity value="1"/>
<costtype>COST_TYPE_PRICE</costtype>
<items>
<item>
<item>CURRENCY_CASH</item>
<quantity value="6000"/>
</item>
</items>
<unlocks/>
</item>
</acquirecosts>
<sellprices>
<item>
<key>SELL_SHOP_DEFAULT</key>
<quantity value="1"/>
<costtype>COST_TYPE_PRICE</costtype>
<items>
<item>
<item>CURRENCY_CASH</item>
<quantity value="6000"/>
</item>
</items>
<unlocks/>
</item>
</sellprices>
</root>
XSLT
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="quantity">
<xsl:choose>
<xsl:when test="preceding-sibling::*='CURRENCY_CASH'">
<xsl:copy>
<xsl:attribute name="value">
<xsl:if test="ancestor::*[local-name() = 'acquirecosts']">
<xsl:value-of select="@value * 2"/>
</xsl:if>
<xsl:if test="ancestor::*[local-name() = 'sellprices']">
<xsl:value-of select="@value * 0.5"/>
</xsl:if>
</xsl:attribute>
</xsl:copy>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
输出XML
<root>
<acquirecosts>
<item>
<key>COST_SHOP_DEFAULT</key>
<quantity value="1" />
<costtype>COST_TYPE_PRICE</costtype>
<items>
<item>
<item>CURRENCY_CASH</item>
<quantity value="12000" />
</item>
</items>
<unlocks />
</item>
</acquirecosts>
<sellprices>
<item>
<key>SELL_SHOP_DEFAULT</key>
<quantity value="1" />
<costtype>COST_TYPE_PRICE</costtype>
<items>
<item>
<item>CURRENCY_CASH</item>
<quantity value="3000" />
</item>
</items>
<unlocks />
</item>
</sellprices>
</root>
c#,XSLT 转换
void Main()
{
const string SOURCEXMLFILE = @"e:\Temp\input.xml";
const string XSLTFILE = @"e:\Temp\process.xslt";
const string OUTPUTXMLFILE = @"e:\temp\output.xml";
try
{
XsltArgumentList xslArg = new XsltArgumentList();
using (XmlReader src = XmlReader.Create(SOURCEXMLFILE))
{
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(XSLTFILE, new XsltSettings(true, true), new XmlUrlResolver());
XmlWriterSettings settings = xslt.OutputSettings.Clone();
settings.IndentChars = "\t";
// to remove BOM
settings.Encoding = new UTF8Encoding(false);
using (XmlWriter result = XmlWriter.Create(OUTPUTXMLFILE, settings))
{
xslt.Transform(src, xslArg, result, new XmlUrlResolver());
result.Close();
}
}
Console.WriteLine("File '{0}' has been generated.", OUTPUTXMLFILE);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
使用 Xml Linq 并进行两次传递
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
XElement acquiredcosts = doc.Descendants("acquirecosts").FirstOrDefault();
List<XElement> currentCash = acquiredcosts.Descendants("item").Where(x => (string)x.Element("item") == "CURRENCY_CASH").ToList();
foreach (XElement c in currentCash)
{
XElement quantity = c.Element("quantity");
quantity.SetAttributeValue("value", 2 * (int)quantity.Attribute("value"));
}
XElement sellPrices = doc.Descendants("sellprices").FirstOrDefault();
currentCash = sellPrices.Descendants("item").Where(x => (string)x.Element("item") == "CURRENCY_CASH").ToList();
foreach (XElement c in currentCash)
{
XElement quantity = c.Element("quantity");
quantity.SetAttributeValue("value", .5 * (int)quantity.Attribute("value"));
}
}
}
}