将一个XML DOM的一部分复制到另一个XML DOM以进行XSL转换(.NET)

时间:2023-01-14 08:02:42

The scope of XML and DOM in .NET 3.5 is so large that I'm having trouble coming up with a simple solution to my problem without using too many lines of messy code. Since people here always come up with some elegant solutions, I thought it would be a good question.

.NET 3.5中的XML和DOM的范围是如此之大,以至于我无法使用简单的解决方案来解决我的问题,而不会使用过多的混乱代码。由于这里的人总是提出一些优雅的解决方案,我认为这将是一个很好的问题。

How do I take in an XML file (that I created and saved earlier in the program) that has n instances of the 'unit' node beneath the root 'report' node to create an XML DOM that has the 'report' values and one 'unit'.

如何接收在根“报告”节点下具有n个“单元”节点实例的XML文件(我在程序中先前创建并保存),以创建具有“报告”值的XML DOM和一个'单元'。

I need to do this for each unit and then create an HTML file using my existing XSL transformation stylesheet on the new XML DOMs. I can already get it to work for all the units (the existing XML file), but I need a report for each unit.

我需要为每个单元执行此操作,然后使用新XML DOM上的现有XSL转换样式表创建HTML文件。我已经可以让它适用于所有单元(现有的XML文件),但我需要为每个单元提供一份报告。

EDIT (per comment request):

编辑(每条评论请求):

What it looks like:

它看起来像什么:

<report>
  <report_name>Name</report_name>
  <report_date>yyyy/mm/dd</report_date>
  <unit>
    <ip>127.0.0.1</ip>
    <label>localhost</label>
    ..etc
  </unit>
  <unit>
    <ip>255.255.255.255</ip>
    <label>broadcast</label>
    ..etc
  </unit>
<report>

And I want each of:

我希望每个人:

<report>
  <report_name>Name</report_name>
  <report_date>yyyy/mm/dd</report_date>
  <unit>
    <ip>127.0.0.1</ip>
    <label>localhost</label>
    ..etc
  </unit>
</report>

and

<report>
  <report_name>Name</report_name>
  <report_date>yyyy/mm/dd</report_date>
  <unit>
    <ip>255.255.255.255</ip>
    <label>broadcast</label>
    ..etc
  </unit>
<report>

2 个解决方案

#1


foreach (XmlElement xmlUnit in xmlMain.SelectNodes("/report/unit"))
{
    var xmlDest = new XmlDocument();
    xmlDest.AppendChild(xmlDest.CreateElement("report"));

    // Add the report properties...
    foreach ( XmlElement xmlValue in xmlMain.SelectNodes( "/report/report_name | /report/report_date" ) )
        xmlDest.DocumentElement.AppendChild(xmlDest.ImportNode(xmlValue, true));

    // Add the "<unit>" element from the main document...
    xmlDest.DocumentElement.AppendChild(xmlDest.ImportNode(xmlUnit, true));

    // Now generate report using xmlDest
}

#2


If you didn't need to access information outside the unit element, you could do this:

如果您不需要访问unit元素之外的信息,则可以执行以下操作:

foreach (XmlNode n in d.SelectNodes("/report/unit"))
{
   using (StringReader sr = new StringReader(n.OuterXml))
   using (XmlReader xr = XmlReader.Create(sr))
   using (XmlWriter xw = XmlWriter.Create(Console.Out))
   {
       xslt.Transform(xr, xw);
   }
}

The downside of this approach is that the XSLT can access only the XML in the selected node. If you need to access XML elsewhere in the document, you need to tell the transform which node to process:

这种方法的缺点是XSLT只能访问所选节点中的XML。如果需要在文档的其他位置访问XML,则需要告知转换要处理的节点:

for (int i = 0; i < d.SelectNodes("/report/unit").Count; i++)
{
    XsltArgumentList args = new XsltArgumentList();
    args.AddParam("position", "", i + 1);
    using (StringReader sr = new StringReader(d.OuterXml))
    using (XmlReader xr = XmlReader.Create(sr))
    using (XmlWriter xw = XmlWriter.Create(Console.Out))
    {
        xslt.Transform(xr, args, xw);
    }
}

...and have your XSLT include the likes of this:

...并让您的XSLT包括以下内容:

<xsl:param name="position"/>
<xsl:template match="/">
    <xsl:apply-templates select="/report/unit[$position=position()]"/>
</xsl:template>

#1


foreach (XmlElement xmlUnit in xmlMain.SelectNodes("/report/unit"))
{
    var xmlDest = new XmlDocument();
    xmlDest.AppendChild(xmlDest.CreateElement("report"));

    // Add the report properties...
    foreach ( XmlElement xmlValue in xmlMain.SelectNodes( "/report/report_name | /report/report_date" ) )
        xmlDest.DocumentElement.AppendChild(xmlDest.ImportNode(xmlValue, true));

    // Add the "<unit>" element from the main document...
    xmlDest.DocumentElement.AppendChild(xmlDest.ImportNode(xmlUnit, true));

    // Now generate report using xmlDest
}

#2


If you didn't need to access information outside the unit element, you could do this:

如果您不需要访问unit元素之外的信息,则可以执行以下操作:

foreach (XmlNode n in d.SelectNodes("/report/unit"))
{
   using (StringReader sr = new StringReader(n.OuterXml))
   using (XmlReader xr = XmlReader.Create(sr))
   using (XmlWriter xw = XmlWriter.Create(Console.Out))
   {
       xslt.Transform(xr, xw);
   }
}

The downside of this approach is that the XSLT can access only the XML in the selected node. If you need to access XML elsewhere in the document, you need to tell the transform which node to process:

这种方法的缺点是XSLT只能访问所选节点中的XML。如果需要在文档的其他位置访问XML,则需要告知转换要处理的节点:

for (int i = 0; i < d.SelectNodes("/report/unit").Count; i++)
{
    XsltArgumentList args = new XsltArgumentList();
    args.AddParam("position", "", i + 1);
    using (StringReader sr = new StringReader(d.OuterXml))
    using (XmlReader xr = XmlReader.Create(sr))
    using (XmlWriter xw = XmlWriter.Create(Console.Out))
    {
        xslt.Transform(xr, args, xw);
    }
}

...and have your XSLT include the likes of this:

...并让您的XSLT包括以下内容:

<xsl:param name="position"/>
<xsl:template match="/">
    <xsl:apply-templates select="/report/unit[$position=position()]"/>
</xsl:template>