代码之家  ›  专栏  ›  技术社区  ›  Jon Galloway

XML文档的松散合并

  •  2
  • Jon Galloway  · 技术社区  · 15 年前

    我有两个文档-一个是自定义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>
    

    我最喜欢使用C、Linq或某种Excel Fu。我想如果必须这样做的话,我可以处理XSLT,只要它不涉及我自己编写太多的XSLT。

    我看过这个问题,但它似乎对我想做的事情没什么帮助: Merge XML documents

    2 回复  |  直到 15 年前
        1
  •  5
  •   Nathan Baulch    15 年前

    听起来像是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>
    
        2
  •  1
  •   Robert Rossney    15 年前

    将其添加到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() 函数来读取它。