XML文档的松散合并

时间:2009-07-30 22:02:34

标签: c# xml linq-to-xml

我有两个文档 - 一个是自定义XML文件格式,另一个是带有一堆自定义扩展的RSS源。我希望在一个元素值匹配的情况下,使用RSS提要中的值填充XML文件中的字段。

这适用于手动运行几次的离线流程 - 它不需要运行良好,只需要容错,等等。手工劳动或干预都可以。

我的主XML文档如下所示:

    <videos>
        <video>
            <title>First Video</title>
            <code>AAA123</code>
            <id>decaf-decaf-decaf-decaf</id>
            <description>lots of text here...</description>
        </video>
        <video>
            <title>Second Video with no code</title>
            <code></code>
            <id>badab-badab-badab-badab</id>
            <description>lots of text here...</description>
        </video>
    </videos>

RSS源是标准的RSS,带有一些额外的字段:

  <ns:code>AAA123</ns:code>
  <ns:type>Awesome</ns:type>
  <ns:group>Wonderful</ns:group>

我想在 value matches the value:

    <videos>
        <video>
            <title>First Video</title>
            <code>AAA123</code>
            <id>decaf-decaf-decaf-decaf</id>
            <description>lots of text here...</description>
            <type>Awesome</type>
            <group>Wonderful</group>
        </video>
        <video>
            <title>Second Video with no code</title>
            <code></code>
            <id>badab-badab-badab-badab</id>
            <description>lots of text here...</description>
            <type></type>
            <group></group>
        </video>
    </videos>
时将RSS文档中的额外字段拉到XML文档中

我最想使用c#,LINQ或某种Excel-fu。我想如果我不得不处理XSLT,只要它不涉及我自己编写很多XSLT。

我看了这个问题,但对我正在尝试做的事情似乎没有任何帮助: Merge XML documents

2 个答案:

答案 0 :(得分:5)

听起来像是LINQ to XML的工作!

var vidDoc = XDocument.Parse(vidXml);
var rssDoc = XDocument.Parse(rssXml);
var videos = vidDoc.XPathSelectElements("/videos/video");
var rssItems = rssDoc.XPathSelectElements("/rss/channel/item");
var matches = videos.Join(
    rssItems,
    video => video.Element(XName.Get("code")).Value,
    rssItem => rssItem.Element(XName.Get("code", "http://test.com")).Value,
    (video, item) => new {video, item});

foreach (var match in matches)
{
    var children = match.item.Elements()
        .Where(child => child.Name.NamespaceName == "http://test.com" &&
                        child.Name.LocalName != "code");

    foreach (var child in children)
    {
        //remove the namespace
        child.Name = XName.Get(child.Name.LocalName);
        match.video.Add(child);
    }
}

vidDoc.Save(Console.Out);

上述解决方案假设RSS文档如下所示:

<rss xmlns:ns="http://test.com" version="2.0">
  <channel>
    <item>
      <title>AAA123</title>
      <link>http://test.com/AAA123</link>
      <pubDate>Sun, 26 Jul 2009 23:59:59 -0800</pubDate>
      <ns:code>AAA123</ns:code>
      <ns:type>Awesome</ns:type>
      <ns:group>Wonderful</ns:group>
    </item>
  </channel>
</rss>

答案 1 :(得分:1)

将此添加到XSLT标识转换(您还需要将http://test.com命名空间的命名空间声明添加到转换的顶级元素中:

<xsl:variable name="rss" select="document('rss.xml')"/>

<xsl:template match="video">
   <xsl:apply-templates select="@* | node()"/>
   <xsl:apply-templates select="$rss/rss/channel/item[ns:code=current()/code]"/>
</xsl:template>

<!-- this keeps the code element from getting copied -->
<xsl:template match="ns:code"/>

<!-- this will copy all of the content of the ns:* elements, not just their text -->
<xsl:template match="ns:*">
   <xsl:element name="{local-name()}">
      <xsl:apply-templates select="@* | node()"/>
   </xsl:element>
</xsl:template>

如果您已经将RSS读入程序中的XmlDocument,则可以将其作为参数传递给XSLT,而不是使用document()函数来读取它。