在LINQ中将2 xmls合并为新XML的有效方法

时间:2011-09-12 12:46:03

标签: c# .net linq

我为每个用户提供了用于管理网站权限的XML,还有一个管理工具可以更新XML以授予/拒绝/修改对新用户或现有用户的访问权

XML的结构类似于

<Security>
  <FiscalYear ID="2011">
    <Country ID="23">
      <State ID="10">
        <City ID="1"></City>
        <City ID="3"></City>
      </State>
    </Country>
  </FiscalYear>
  <FiscalYear ID="2010">
    <Country ID="13">
      <State ID="20">
        <City ID="11"></City>
        <City ID="32"></City>
      </State>
    </Country>
  </FiscalYear>
</Security>

现在,如果管理员想要授予新会计年度2012的许可,我将获得这样的输入

<FiscalYear ID="2012">
    <Country ID="13">
      <State ID="20">
        <City ID="11"></City>
        <City ID="32"></City>
      </State>
    </Country>
  </FiscalYear>

因此,这个将作为新节点附加到现有节点 或者如果他想修改现有权限

<FiscalYear ID="2011">
    <Country ID="13">
      <State ID="20">
        <City ID="11"></City>
        <City ID="32"></City>
      </State>
    </Country>
  </FiscalYear>

这个用于修改权限,意味着授予用户访问状态20和城市11和32

的权限

我是否可以遵循我的合并数据的最佳方式或示例

3 个答案:

答案 0 :(得分:2)

如果您只想附加一个新节点,这很简单:

var xmlDocument = XDocument.Parse(xmlParentStr);
var xmlToAdd = XElement.Parse(xmlToAddStr);

if (null != xmlDocument.Element("Security"))
  xmlDocument.Element("Security").AddFirst(xmlToAdd);

其中xmlParentStr是一个字符串,其中包含您首次出现的xml,以及2011和2010 FiscalYear标记。 xmlToAdd是2012年会计年度的xml字符串。这将为您提供:

<Security>
  <FiscalYear ID="2012">
    <Country ID="13">
      <State ID="20">
        <City ID="11"></City>
        <City ID="32"></City>
      </State>
    </Country>
  </FiscalYear>
  <FiscalYear ID="2011">
    <Country ID="23">
      <State ID="10">
        <City ID="1"></City>
        <City ID="3"></City>
      </State>
    </Country>
  </FiscalYear>
  <FiscalYear ID="2010">
    <Country ID="13">
      <State ID="20">
        <City ID="11"></City>
        <City ID="32"></City>
      </State>
    </Country>
  </FiscalYear>
</Security>

顺便说一句,还有其他各种方法可以将xml加载到XDocument或XElement中。例如XDocument.Load()和XElement.Load,它们可以从FileStream,URI或Reader中提取它。

如果您想更改2011年的国家/地区ID,可以通过以下方式轻松完成:

var elementToChange=xmlDocument
  .Descendants()
  .Where(x => x.Name.LocalName=="FiscalYear" && x.Attribute("ID")!=null && x.Attribute("ID").Value=="2011");

foreach(var element in elementToChange) {
  var changes = element.Descendants().Where(x => x.Name.LocalName == "Country" && x.Attribute("ID").Value == "23");
  foreach(var change in changes) {
    change.Attribute("ID").SetValue("1337");
  }
}

然后会产生:

<Security>
  <FiscalYear ID="2012">
    <Country ID="13">
      <State ID="20">
        <City ID="11"></City>
        <City ID="32"></City>
      </State>
    </Country>
  </FiscalYear>
  <FiscalYear ID="2011">
    <Country ID="1337">
      <State ID="10">
        <City ID="1"></City>
        <City ID="3"></City>
      </State>
    </Country>
  </FiscalYear>
  <FiscalYear ID="2010">
    <Country ID="13">
      <State ID="20">
        <City ID="11"></City>
        <City ID="32"></City>
      </State>
    </Country>
  </FiscalYear>
</Security>

我将您需要的值更改为“1337”,因为它更容易看到,但原理是相同的。你可以继续以这种方式走下树。 (以下代码会更改匹配的每个条目,如果您决定只更改第一个条目或者知道您只有一个,您可以通过使用.FirstOrDefault()来简化上述代码并摆脱foreach循环< / p>

答案 1 :(得分:1)

// untested
var masterDoc = XDocument.Load(...);
var updateDoc = XDocument.Load(...);

foreach (var year in updateDoc.Root.Descendants("FiscalYear"))
{
    var oldYear = masterDoc.Root.Descendants("FiscalYear")
              .Where(y => y.Attributes["ID"].Value == year.Attributes["ID"].Value)
              .FirstOrDefault() ;
    if (oldYear == null)
    {
         masterDoc.Root.Add(new XElement(....));
    }
    else
    {
        // nested properties
    }
}

答案 2 :(得分:0)

我发布了我的要求的工作版本:)

        XDocument currentPermission = XDocument.Parse(xmlParentStr);
        XDocument newPermission = XDocument.Load(xmlToAddStr);

        int fyValue = 2012, countryId = 205, stateId = 0, cityId = 0;
        //check whether user has access for this fiscal year or not
        IEnumerable<XElement> fyList = from fyNode in currentPermission.Descendants("FiscalYear")
                                       where (int)fyNode.Attribute("Name") == fyValue
                                       select fyNode;

        if (null != fyList && fyList.Count() > 0) //Fiscal year present, means user is trying to modify permissions for the given fiscal year
        {
            //Check whether user has access for this country or not
            IEnumerable<XElement> countryList = from subNode in fyList.Descendants("Country")
                                                   where (int)subNode.Attribute("ID") == countryId
                                                   select subNode;
            if (null != countryList && countryList.Count() > 0) //country present, means user is trying to modify permissions for a country
            {
                IEnumerable<XElement> stateList = from mbpNode in countryList.Descendants("State")
                                                     where (int)mbpNode.Attribute("ID") == stateId
                                                     select mbpNode;

                if (stateId != 0 && null != stateList && stateList.Count() > 0)
                {
                    IEnumerable<XElement> cityList = from mbpNode in stateList.Descendants("City")
                                                            where (int)mbpNode.Attribute("ID") == stateId
                                                            select mbpNode;

                    if (cityId != 0 && null != cityList && cityList.Count() > 0)
                    {
                        // User already have access, nothing to do
                    }
                    else
                    {

                        currentPermission.Elements("FiscalYear")
                        .Where(t => t.Attribute("Name").Value == fyValue.ToString())
                        .Elements("Country")
                        .Where(t => t.Attribute("ID").Value == countryId.ToString())
                        .Elements("State")
                        .Where(t => t.Attribute("ID").Value == stateId.ToString())
                        .Single()
                        .Add(newPermission.Descendants("City"));

                    }
                }
                else
                {

                    currentPermission.Elements("FiscalYear")
                    .Where(t => t.Attribute("Name").Value == fyValue.ToString())
                    .Elements("Country")
                    .Where(t => t.Attribute("ID").Value == countryId.ToString())
                    .Single()
                    .Add(newPermission.Descendants("State"));
                }
            }
            else //Country is not present means user is granted permissions for this country
            {

                currentPermission.Elements("FiscalYear")
                    .Where(t => t.Attribute("Name").Value == fyValue.ToString())
                    .Single()
                    .Add(newPermission.Descendants("Country"));

            }
        }
        else //fiscal year is not present, it means user is trying to add permissions for a new fiscal year
        {
            //string newPermissionXML = CreatePermissionXML(newUserPermission);
            currentPermission.Add(newPermission.Descendants("FiscalYear"));
        }