【问题标题】:Efficient way to filter part of an XML document过滤部分 XML 文档的有效方法
【发布时间】:2011-05-05 10:33:35
【问题描述】:

我正在寻找一种过滤 XML 文档的有效方法。我正在使用 C#/.NET。假设我有以下原始文件:

<Bookstores>
   <Bookstore>
      <StoreName>Store 1</StoreName>
      <Books>
         <Book>
            <Author>Bob</Author>
            <Title>ABC</Title>
         </Book> 
         <Book>
            <Author>John</Author>
            <Title>XYZ</Title>
         </Book> 
      </Books>
   </Bookstore>
</Bookstores>

我在其他地方存储了另一个部分文档:

<Book>
   <Author>John</Author>
   <Title>XYZ</Title>
</Book> 

使用这两个文档,我需要输出第二个部分 XML 文档,包括它的原始祖先。

<Bookstores>
   <Bookstore>
      <StoreName>Store 1</StoreName>
      <Books>
         <Book>
            <Author>John</Author>
            <Title>XYZ</Title>
         </Book> 
      </Books>
   </Bookstore>
</Bookstores>

我也愿意通过其他方式来做到这一点。我有一个无法直接操作的原始文档。我需要单独存储对该文档部分的“引用”。然后我需要使用“参考”过滤/翻译原始文档以进行显示。

【问题讨论】:

  • 所以您想复制第一个 XML 文档,但过滤掉除第二个 XML 文档中的书籍之外的所有书籍?
  • 是的,这就是我想要完成的。
  • 好问题,+1。有关完整而简短的 XSLT 解决方案,请参阅我的答案。

标签: c# .net xml xslt .net-3.5


【解决方案1】:

请尝试使用 LINQ to XML, http://www.hookedonlinq.com/LINQtoXML5MinuteOverview.ashx.

我希望这会有所帮助。

【讨论】:

    【解决方案2】:

    此 XSLT 转换

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:variable name="vrtfReference">
         <Book>
           <Author>John</Author>
           <Title>XYZ</Title>
         </Book>
     </xsl:variable>
    
     <xsl:variable name="vReference" select=
     "document('')/*/xsl:variable
                      [@name='vrtfReference']/*"/>
    
     <xsl:template match="node()|@*" name="identity">
      <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
     </xsl:template>
    
     <xsl:template match="Book">
    
       <xsl:apply-templates mode="copy" select=
        "self::node()[$vReference
                       [Author = current()/Author
                      and
                       Title = current()/Title
                       ]
                      ]
        "/>
     </xsl:template>
    
     <xsl:template match="node()" mode="copy">
      <xsl:call-template name="identity"/>
     </xsl:template>
    </xsl:stylesheet>
    

    应用于提供的 XML 文档时

    <Bookstores>
       <Bookstore>
          <StoreName>Store 1</StoreName>
          <Books>
             <Book>
                <Author>Bob</Author>
                <Title>ABC</Title>
             </Book>
             <Book>
                <Author>John</Author>
                <Title>XYZ</Title>
             </Book>
          </Books>
       </Bookstore>
    </Bookstores>
    

    产生想要的正确结果

    <Bookstores>
       <Bookstore>
          <StoreName>Store 1</StoreName>
          <Books>
             <Book>
                <Author>John</Author>
                <Title>XYZ</Title>
             </Book>
          </Books>
       </Bookstore>
    </Bookstores>
    

    请注意

    1. 身份规则用于“按原样”复制任何节点,但与参考文档中的相同 Book 元素不匹配的 Book 元素除外。 p>

    2. 匹配 Book 的模板决定复制当前节点(通过对其应用身份规则)仅当两个子节点(AuthorTitle)与参考文档中某些 Book 元素的子元素具有相同的值

    3. 为方便起见,我将参考文档嵌入到 XSLT 样式表中。实际上,它将位于自己的 XML 文件中,只需对 $vReference 变量的定义稍作更改即可。

    【讨论】:

    • 说我的过滤器中有多个 Book 记录。这也行吗?
    • @Matt:是的,只有与引用文件中的一个相同的 Book 元素会保留在文档中。
    猜你喜欢
    • 2017-02-27
    • 2012-04-22
    • 2017-09-29
    • 2014-09-02
    • 2012-08-20
    • 1970-01-01
    • 1970-01-01
    • 2010-12-07
    • 1970-01-01
    相关资源
    最近更新 更多