繁体   English   中英

使用 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"));
            }
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM