在LINQ中合并两个XML到一个新的XML的有效方法
本文关键字:XML 方法 一个 有效 两个 LINQ 合并 | 更新日期: 2023-09-27 18:08:14
我有用于管理网站权限的每个用户的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
是否有最好的方式或例子,我可以按照我的要求合并数据
如果您只是想附加一个新节点,这很简单:
var xmlDocument = XDocument.Parse(xmlParentStr);
var xmlToAdd = XElement.Parse(xmlToAddStr);
if (null != xmlDocument.Element("Security"))
xmlDocument.Element("Security").AddFirst(xmlToAdd);
其中xmlParentStr是一个字符串,其中包含您第一次呈现的xml,带有2011和2010财年标记。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。加载,可以从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())
// 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
}
}
我正在发布我的需求的工作版本:)
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"));
}