【问题标题】:Easiest way to add xml a node with a bunch of children nodes in .Net?在.Net中添加带有一堆子节点的节点的最简单方法?
【发布时间】:2011-11-03 10:53:57
【问题描述】:

我需要修改一个 xml 文件(实际上是一个 .rdlc 报告文件)并添加一些具有很多子节点的节点(并且这些子节点又具有子节点)。实际上它们几乎是相同的结构,就像这个:

           <TablixRow>
            <Height>0.23622in</Height>
            <TablixCells>
              <TablixCell>
                <CellContents>
                  <Textbox Name="Textbox1">
                    <CanGrow>true</CanGrow>
                    <KeepTogether>true</KeepTogether>
                    <Paragraphs>
                      <Paragraph>
                        <TextRuns>
                          <TextRun>
                            <Value/>
                            <Style/>
                          </TextRun>
                        </TextRuns>
                        <Style/>
                      </Paragraph>
                    </Paragraphs>
                    <rd:DefaultName>Textbox1</rd:DefaultName>
                    <Style>
                      <Border>
                        <Style>None</Style>
                      </Border>
                      <PaddingLeft>2pt</PaddingLeft>
                      <PaddingRight>2pt</PaddingRight>
                      <PaddingTop>2pt</PaddingTop>
                      <PaddingBottom>2pt</PaddingBottom>
                    </Style>
                  </Textbox>
                </CellContents>
              </TablixCell>
              <TablixCell>
                <CellContents>
                  <Textbox Name="Textbox5">
                    <CanGrow>true</CanGrow>
                    <KeepTogether>true</KeepTogether>
                    <Paragraphs>
                      <Paragraph>
                        <TextRuns>
                          <TextRun>
                            <Value/>
                            <Style/>
                          </TextRun>
                        </TextRuns>
                        <Style/>
                      </Paragraph>
                    </Paragraphs>
                    <rd:DefaultName>Textbox5</rd:DefaultName>
                    <Style>
                      <Border>
                        <Style>None</Style>
                      </Border>
                      <PaddingLeft>2pt</PaddingLeft>
                      <PaddingRight>2pt</PaddingRight>
                      <PaddingTop>2pt</PaddingTop>
                      <PaddingBottom>2pt</PaddingBottom>
                    </Style>
                  </Textbox>
                </CellContents>
              </TablixCell>
            </TablixCells>
          </TablixRow>

那么最简单的方法是什么?在正常情况下,我只创建一个 XmlNode 和一些 XmlAttribute 对象,将这些属性附加到节点,并以相同的方式创建子节点,最后将每个子节点附加到其父节点中。不用说,处理我的示例节点会很乏味。有更简单的方法吗?与 XmlDocument 类一样,有一个函数 LoadXml (xml as string),它将一个字符串作为整个 xml 文件并构造结构。有没有类似的方法来构造一个 XmlNode 对象?这样我只需要提供代表我的节点的整个字符串,然后导航到我需要更改值的子节点。谢谢!

更新: 我正在使用 VB.NET。使用 XElement 时命名空间存在一个问题。在这个链接 XName Class,它说对于 C#,建议只使用覆盖的 add 运算符来组合元素和 NS,但对于 VB,它建议在顶部使用 Import(在模块外部的示例中。我认为它也应该适用于类)然后一切都会自动使用这个 NS。然而,这种情况并非如此。例如,如果我给

             Dim para As XElement = _
                <ReportParameter Name="HasErr">
                    <DataType>Boolean</DataType>
                    <DefaultValue>
                        <Values>
                            <Value>False</Value>
                        </Values>
                    </DefaultValue>
                    <Prompt>ReportParameter1</Prompt>
                </ReportParameter>

它会自动将我指定的(并作为默认)附加到那里。但是如果我使用 XElement.Parse(xml As String),其中 xml 是表示 xml 的相同字符串,它根本不会添加这个 NS,这最终会使用一个空的 NS(我想使用 XElement.解析是我想在那里提供我的自定义参数值,例如 & MY_TYPE_NAME & )。 第二个问题是在使用@JohnD 的代码时,我尝试了

xdoc.Root.Elements("ReportParameters").FirstOrDefault()

我假设它也将使用我声明的和默认的 NS,不会返回任何内容,即它在空命名空间中搜索,但它实际上在我提到的 NS 中。

任何人都知道这就是 MS 这样做的原因,所以没有 XName 类的构造函数,我可以在使用它之前指定一个命名空间吗?它说只有一个隐式转换,所以当在

中给出一个表示元素名称的字符串时
xdoc.Root.Elements("ReportParameters")

它将隐式生成一个 XName 对象来索引 Elements 中的搜索。但这真的很笨拙。

最新更新: 我现在找到了解决我在更新中的第一个问题的解决方案:我现在使用 XML Literals 来创建 XElement,并且可以在其中使用表达式。所以它现在看起来像这样:

 Dim paraDefNode As XElement = _
                <ReportParameter Name=<%= para.Value %>>
                    <DataType>String</DataType>
                    <DefaultValue>
                        <Values>
                            <Value>False</Value>
                        </Values>
                    </DefaultValue>
                    <Prompt>ReportParameter1</Prompt>
                </ReportParameter>

它会添加我指定的 NS。 (就像我说的,XElement.Parse(string) 不会添加它)所以现在我可以构造正确的节点了。对于我的第二个问题,我仍然无法弄清楚:我无法使用元素名称导航到目标节点,因为它不会搜索正确的 NS。

无论如何我都会将@JohnD 的帖子标记为答案,因为他建议使用 LINQ to XML。

【问题讨论】:

    标签: xml vb.net xmlnode


    【解决方案1】:

    如果您可以使用 .NET 4,我建议您查看 XDocument。下面是向文档添​​加元素的示例:

    http://msdn.microsoft.com/en-us/library/system.xml.linq.xdocument.add.aspx

    您可以使用XDocument.Parse 从字符串初始化文档,或使用XDocument.Load 从文件初始化(还有其他重载)。

    然后,您可以导航到要插入的元素,然后执行XElement.Add()

    这里是一些将您的 XML 元素放入另一个 XDocument 的示例代码。我只是将 XML 添加到目标 XDcoument 的第一个“Elem”节点,但您可以调整代码以多次添加,等等...

            public static void Main()
            {
    
                var xelementToAdd = XElement.Parse(@"
                    <TablixRow>
                        <Height>0.23622in</Height>
                        <TablixCells>
                          <TablixCell>
                            <CellContents>
                              <Textbox Name='Textbox1'>
                                <CanGrow>true</CanGrow>
                                <KeepTogether>true</KeepTogether>
                                <Paragraphs>
                                  <Paragraph>
                                    <TextRuns>
                                      <TextRun>
                                        <Value/>
                                        <Style/>
                                      </TextRun>
                                    </TextRuns>
                                    <Style/>
                                  </Paragraph>
                                </Paragraphs>
                                <DefaultName>Textbox1</DefaultName>
                                <Style>
                                  <Border>
                                    <Style>None</Style>
                                  </Border>
                                  <PaddingLeft>2pt</PaddingLeft>
                                  <PaddingRight>2pt</PaddingRight>
                                  <PaddingTop>2pt</PaddingTop>
                                  <PaddingBottom>2pt</PaddingBottom>
                                </Style>
                              </Textbox>
                            </CellContents>
                          </TablixCell>
                          <TablixCell>
                            <CellContents>
                              <Textbox Name='Textbox5'>
                                <CanGrow>true</CanGrow>
                                <KeepTogether>true</KeepTogether>
                                <Paragraphs>
                                  <Paragraph>
                                    <TextRuns>
                                      <TextRun>
                                        <Value/>
                                        <Style/>
                                      </TextRun>
                                    </TextRuns>
                                    <Style/>
                                  </Paragraph>
                                </Paragraphs>
                                <DefaultName>Textbox5</DefaultName>
                                <Style>
                                  <Border>
                                    <Style>None</Style>
                                  </Border>
                                  <PaddingLeft>2pt</PaddingLeft>
                                  <PaddingRight>2pt</PaddingRight>
                                  <PaddingTop>2pt</PaddingTop>
                                  <PaddingBottom>2pt</PaddingBottom>
                                </Style>
                              </Textbox>
                            </CellContents>
                          </TablixCell>
                        </TablixCells>
                      </TablixRow>");
    
                // you might use XDocument.Load() here instead of Parse()
                var xdoc = XDocument.Parse(@"
    <Report xmlns='http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition' 
            xmlns:rd='http://schemas.microsoft.com/SQLServer/reporting/reportdesigner'
            xmlns:msxsl='urn:schemas-microsoft-com:xslt'
            xmlns:xs='http://www.w3.org/2001/XMLSchema' 
            xmlns:msdata='urn:schemas-microsoft-com:xml-msdata'>
        <rd:DrawGrid>true</rd:DrawGrid>
        <ReportParameters></ReportParameters>
    </Report>
                ");
    
                XNamespace ns1 = "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition";
                XNamespace ns2 = "http://schemas.microsoft.com/SQLServer/reporting/reportdesigner";
                XNamespace ns3 = "urn:schemas-microsoft-com:xslt";
                XNamespace ns4 = "http://www.w3.org/2001/XMLSchema";
                XNamespace ns5 = "urn:schemas-microsoft-com:xml-msdata";
    
                var e = xdoc.Root.Elements(ns1 + "ReportParameters")
                    .FirstOrDefault();
    
                e.Add(xelementToAdd);
                xdoc.Save(@"c:\temp\foo2.xml");
            }
    

    为了它的价值,我调整了您的示例 XML 以删除名称空间前缀(名称空间是一个与您的问题分开的问题)并用单引号替换了双引号(XML 在其他方面是等效的)。

    更新:是的,您遇到了命名空间问题。即使您的&lt;ReportParameters&gt; 元素没有&lt;rd:DrawGrid&gt; 之类的前缀,它也使用默认命名空间,您必须指定它。查看更新的示例,它应该可以满足您的需求。希望这会有所帮助!

    【讨论】:

    • 感谢您的回复,否则您的回答很清楚,但我在命名空间上苦苦挣扎。一方面,当我使用您的代码xdoc.Root.Elements("MY_ELEMENT_NAME").FirstOrDefault() 时,它什么也不返回。我猜它与命名空间有关,我需要为这个 XName 对象指定命名空间来搜索。可悲的是,我找不到任何例子。此链接:link 没有给出如何在代码中间使用 XName 对象的示例。
    • 其次,我想我还需要指定要添加的 XElement 的命名空间(在您的示例中,对于 xelementToAdd),如果它在一个 NS 之下,对吗?谢谢!
    • 您可以发布您尝试插入的 XML 的 sn-p 吗? (有 MY_ELEMENT_NAME 的那个)?
    • 当然。这里是 sn-p:&lt;Report xmlns="http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition" xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"&gt;&lt;rd:DrawGrid&gt;true&lt;/rd:DrawGrid&gt; &lt;ReportParameters&gt;...&lt;/ReportParameters&gt; 我需要在 下再添加一个节点 。但是,在我加载 xml 文件后,当我尝试 xmldoc.Root.Elements("ReportParameters").FirstOrDefault()
    • 它什么也不返回。但是如果我尝试xmldoc.Root.Elements().FirstOrDefault(),它会返回节点&lt;rd:DrawGrid&gt;true&lt;/rd:DrawGrid&gt; 。所以我猜它与NS有关
    猜你喜欢
    • 2010-10-14
    • 1970-01-01
    • 2018-07-25
    • 1970-01-01
    • 2014-04-20
    • 1970-01-01
    • 2019-01-20
    • 1970-01-01
    • 2012-11-19
    相关资源
    最近更新 更多