0

我需要修改一个 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(在模块外部的示例中。我认为它也应该为 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.解析是我想在那里提供我的自定义参数值,例如 & 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。

4

1 回答 1

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>元素没有前缀 like <rd:DrawGrid>,它也使用默认命名空间,您必须指定它。查看更新的示例,它应该可以满足您的需求。希望这可以帮助!

于 2011-11-03T11:02:19.700 回答