在XmlDocument对象中,如何确保节点集合中的某个子节点存在且有值?

后端开发 2026-07-12

我正在维护一段代码,用于处理位于 System.Xml 命名空间中的 XmlDocument 类型对象。问题在于确保以下XML中的 <price> 元素既存在又有值。该元素或其值可能缺失的情况有多种:

<?xml version="1.0"?>
<catalog>
   <book id="bk101">
      <author>Gambardella, Matthew</author>
      <title>XML Developer's Guide</title>
      <genre>Computer</genre>
      <price></price>
      <publish_date>2000-10-01</publish_date>
      <description>An in-depth look at creating applications 
      with XML.</description>
   </book>
   <book id="bk102">
      <author>Ralls, Kim</author>
      <title>Midnight Rain</title>
      <genre>Fantasy</genre>
      <price />
      <publish_date>2000-12-16</publish_date>
      <description>A former architect battles corporate zombies, 
      an evil sorceress, and her own childhood to become queen 
      of the world.</description>
   </book>
   <book id="bk103">
      <author>Corets, Eva</author>
      <title>Maeve Ascendant</title>
      <genre>Fantasy</genre>
      <publish_date>2000-11-17</publish_date>
      <description>After the collapse of a nanotechnology 
      society in England, the young survivors lay the 
      foundation for a new society.</description>
   </book>
   <book id="bk104">
      <author>Corets, Eva</author>
      <title>Oberon's Legacy</title>
      <genre>Fantasy</genre>
      <price>5.95</price>
      <publish_date>2001-03-10</publish_date>
      <description>In post-apocalypse England, the mysterious 
      agent known only as Oberon helps to create a new life 
      for the inhabitants of London. Sequel to Maeve 
      Ascendant.</description>
   </book>
    </catalog>

我的目标是在缺失时添加 <price> 元素;或者如果它已经存在但没有值,则赋予一个值。

如果我按照 这篇帖子 的方法并使用如下方式:

Private Function EnsureValidPrice(xmlDoc As XmlDocument) As XmlDocument
  Dim bookNodes = xmlDoc.SelectNodes("//book")
  For Each book As XmlNode In bookNodes
    Dim priceNode = book("price")
    If priceNode Is Nothing OrElse String.IsNullOrWhiteSpace(priceNode.InnerText) Then
        Dim ele As XmlNode = xmlDoc.CreateElement("price")
        ele.InnerText = GetPrice(book.Attributes("id"))
        book.AppendChild(ele)
    End If
  Next
  Return xmlDoc
End Function

具有 id="bk101"id="bk102" 的书籍的价格将仍然为空。

应该用一种简洁的方式覆盖这段XML中可能出现的条件?

解决方案

The price for the books with id="bk101" and id="bk102" will remain blank.

在这两种情况下,<price> 元素都存在,因此 priceNode Is Nothing 将返回False,接着 String.IsNullOrWhiteSpace(priceNode.InnerText) 将返回True,因此你会为 InnerText 赋值。

但是,你的代码的问题在于,当你对 InnerText 进行赋值时,你也在无条件地调用 CreateElement()AppendChild(),因此你会在这些书中创建第二个 <price> 元素,然后为该新元素设置 InnerText,而不是对原本已经存在的元素进行设置。下次你再尝试读取这些书的价格时,会发现第一个空的 <price> 元素,而不是第二个已填充的 <price> 元素。

我会修改你的代码,先仅在确实缺失时创建一个空的 <price> 节点,然后再根据该元素的值判断它是已经存在还是新创建的,例如:

Private Function EnsureValidPrice(xmlDoc As XmlDocument) As XmlDocument
  Dim bookNodes = xmlDoc.SelectNodes("//book")
  For Each book As XmlNode In bookNodes
    Dim priceNode as XmlNode = book("price")
    If priceNode Is Nothing Then
      priceNode = xmlDoc.CreateElement("price")
      book.AppendChild(priceNode)
    End If
    If String.IsNullOrWhiteSpace(priceNode.InnerText) Then
      priceNode.InnerText = GetPrice(book.Attributes("id"))
    End If
  Next
  Return xmlDoc
End Function

更新:

或者,如果你需要保持更新后书籍的结构(即 <price> 插在 <genre><publish_date> 之间),请改用 InsertAfter()/InsertBefore() 而不是 AppendChild(),例如:

Private Function EnsureValidPrice(xmlDoc As XmlDocument) As XmlDocument
  Dim bookNodes = xmlDoc.SelectNodes("//book")
  For Each book As XmlNode In bookNodes
    Dim priceNode as XmlNode = book("price")
    If priceNode Is Nothing Then
      priceNode = xmlDoc.CreateElement("price")
      Dim refNode as XmlNode = book("genre")
      If refNode IsNot Nothing Then
        book.InsertAfter(priceNode, refNode)
      Else
        refNode = book("publish_date")
        If refNode IsNot Nothing Then
          book.InsertBefore(priceNode, refNode)
        Else
          book.AppendChild(priceNode)
        End If
      End If
    End If
    If String.IsNullOrWhiteSpace(priceNode.InnerText) Then
      priceNode.InnerText = GetPrice(book.Attributes("id"))
    End If
  Next
  Return xmlDoc
End Function
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章