如何解决使用 C# 批量编辑 XML 中的特定元素
我有一个 .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>
<.>中的“CURRENCY_CASH”数量值乘以2,<.>中的“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"));
}
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。