在自我之前获取元素

本文关键字:获取 元素 自我 | 更新日期: 2023-09-27 18:35:42

如果当前的"Name"元素为空或空,则应采用前一个元素的"Name"值。第一个元素名称永远不会为 null 或空。

我需要获取前面的元素"名称"值,其中当前"名称"元素值为空或空:

List<ScripTbl> ScripData = ScrpHldNode.Descendants(ns + "Scrp").Select(x => new ScripTbl
{
    ID = sID,
    //need help with the line below....
    ScripShare = (!string.IsNullOrEmpty((String)x.Element(ns + "Name")) ? (String)x.Element(ns + "Name") : (x.ElementsBeforeSelf().Count() > 0 ? (String)x.ElementsBeforeSelf().Last().Element(ns + "Name") : "")),
    ScripOpenBalanceDue = (String)x.Element(ns + "OpBal"),
    ScripClosingBalance = (String)x.Element(ns + "ClBal"),
    ScripTransaction = (String)x.Element(ns + "Tran"),
    ScripMovement = (String)x.Element(ns + "Move"),
    ScripFooter = sScripFooter,
    Seq = x.ElementsBeforeSelf().Count() + 1,
    ScripSectorCode = (String)x.Element(ns + "SecCde"),
    ScripClosingPrice = (String)x.Element(ns + "ClPrce"),
    SplitIndicator = (!string.IsNullOrEmpty((String)x.Element(ns + "Name")) ? (x.ElementsBeforeSelf().Count() > 0 && (String)x.Element(ns + "Name") == (String)x.ElementsBeforeSelf().Last().Element(ns + "Name") ? "1" : "0") : "0")
}).ToList();

和 XML:

<ScrpHld xmlns="http://www.website.co.za/namespace">
<Scrp>
    <Name>Company Name Number 1</Name>
    <SecCde>1366J</SecCde>
    <Tran>SOLD</Tran>
    <OpBal>0</OpBal>
    <Move>-2000</Move>
</Scrp>
<Scrp>
    <Tran>ELECTRONIC SETTLEMENT</Tran>
    <Move>2000</Move>
    <ClPrce>25045.00</ClPrce>
    <ClBal>0</ClBal>
</Scrp>
<Scrp>
    <Name>Company Name Number 2</Name>
    <SecCde>1313J</SecCde>
    <Tran>SOLD</Tran>
    <OpBal>10000</OpBal>
    <Move>-90500</Move>
</Scrp>
<Scrp>
    <Tran>ELECTRONIC SETTLEMENT</Tran>
    <Move>80500</Move>
    <ClPrce>3392.00</ClPrce>
    <ClBal>0</ClBal>
</Scrp> 
</ScrpHld>

在自我之前获取元素

使用 PreviousNode 而不是 ElementsBeforeSelf ,它会更容易。我分成多行只是为了增加答案的可读性。

该行应如下所示

ScripShare = (x.Element(ns + "Name") != null 
                 ? (string)x.Element(ns + "Name")
                 : (x.PreviousNode != null
                          ? ((XElement)x.PreviousNode).Element(ns + "Name").Value
                          : string.Empty)),

如果您的xml将在元素中包含注释或任何其他文本,则应检查上一个节点是否为XElement类型,而不是coment(XComent)或文本(XText),那么在这种情况下,使用ElementsBeforeSelf

ScripShare = (x.Element(ns + "Name") != null 
                     ? (string)x.Element(ns + "Name")
                     : (x.NodesBeforeSelf().Last(e => e.NodeType == XmlNodeType.Element) != null
                              ? ((XElement)x.NodesBeforeSelf().Last(e => e.NodeType == XmlNodeType.Element)).Element(ns + "Name").Value
                              : string.Empty)),

试试这个:

    private static string ns = "{http://www.website.co.za/namespace}";
    private static string getName(XElement x) {
        if (x == null)
            throw new InvalidOperationException("First elements has no Name");
        var val = (string) x.Element(ns + "Name");
        return val ?? getName((XElement)x.PreviousNode);
    }
    static void Main(string[] args)
    {
        string xml = @"<ScrpHld xmlns=""http://www.website.co.za/namespace"">
        <Scrp>
            <Name>Company Name Number 1</Name>
            <SecCde>1366J</SecCde>
            <Tran>SOLD</Tran>
            <OpBal>0</OpBal>
            <Move>-2000</Move>
        </Scrp>
        <Scrp>
            <Tran>ELECTRONIC SETTLEMENT</Tran>
            <Move>2000</Move>
            <ClPrce>25045.00</ClPrce>
            <ClBal>0</ClBal>
        </Scrp>
        <Scrp>
            <Name>Company Name Number 2</Name>
            <SecCde>1313J</SecCde>
            <Tran>SOLD</Tran>
            <OpBal>10000</OpBal>
            <Move>-90500</Move>
        </Scrp>
        <Scrp>
            <Tran>ELECTRONIC SETTLEMENT</Tran>
            <Move>80500</Move>
            <ClPrce>3392.00</ClPrce>
            <ClBal>0</ClBal>
        </Scrp> 
        </ScrpHld>";
        XDocument doc = XDocument.Parse(xml);
        var result = doc.Descendants(ns + "Scrp").Select(x => new
            {
                Name = getName(x)
            });
        foreach (var item in result)
        {
            Console.WriteLine(item.Name);
        }

此方法使用递归方法,因此即使两个连续的元素没有名称,它们也将具有前一个元素的名称。

您可以声明用于捕获选择方法范围之外的当前名称的变量:

string name = "";
scripData = ScrpHldNode.Descendants(ns + "Scrp")
                       .Select(scrp => {
                            var currentName = (string)scrp.Element(ns + "Name");
                            if (!String.IsNullOrEmpty(currentName))
                                name = currentName;
                            return new ScripTbl {
                                ScripShare = name
                                // ...
                            };
                       });
没有

递归,没有遍历先前元素的 xml 树。


如果只需要检查缺少的名称元素,则可以将代码缩短为

string name = "";
var scripData = from scrp in ScrpHldNode.Descendants(ns + "Scrp")
                let currentName = (string)scrp.Element(ns + "Name") ?? name
                select new ScripTbl {
                     ScripShare = (name = currentName)
                     // ...
                };

它更短(由于 null 合并运算符的使用和 ScripShare 分配期间棘手的名称分配),但我会使用更长、更明显的代码。