最简单的方法是在.Net中添加带有一堆子节点的xml节点?

时间:2011-11-03 10:53:57

标签: xml vb.net xmlnode

我需要修改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#,建议只使用overriden add运算符来组合元素和NS,但对于VB,它建议在顶部使用Import(在模块外部的示例中。我假设它也应该为Class工作,然后一切都会自动使用这个NS。然而,这种情况并非如此。例如,如果我给出

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

它将自动附加我指定的(并声明为默认值)NS。但是如果我使用XElement.Parse(xml As String),其中xml是表示xml的相同字符串,它根本不会添加此NS,最终将使用空NS(我想使用XElement的原因)。解析我想在那里提供我的自定义参数值,例如&amp; MY_TYPE_NAME&amp;)。 第二个问题是当使用@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。

1 个答案:

答案 0 :(得分:3)

如果您可以使用.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在其他方面是等效的)。

更新:是的,您遇到了命名空间问题。即使您的<ReportParameters>元素没有像<rd:DrawGrid>这样的前缀,它也使用默认命名空间,您必须指定它。看看更新的样本,它应该做你想要的。希望这有帮助!