【问题标题】:XmlNode clone() very slow in XPath queries in XMLXmlNode clone() 在 XML 中的 XPath 查询中非常慢
【发布时间】:2011-05-09 21:25:34
【问题描述】:

我有一个要求,其中有一个大的 XML 文档。我必须根据某些条件从文档中使用 XPath 选择很多节点。然后在我选择 XmlNodes 之后,我必须将新属性添加到所选节点并将其插入回 XmlDocument 中的许多位置。

我发现当我修改选定的 XmlNode 时,实际的 XmlDocument 也会被修改。 所以我想到在整个选定的 XmlNodes 列表上使用 xmlNode.Clone() 方法但是真的非常非常慢。我的意思是有更好的方法吗?还是克隆真的很慢??
顺便说一下,我正在使用 XmlDocument 来加载 Xml 文档。

在此处编辑 :::

我正在为我的问题添加更多详细信息。我使用 C# 语言和 .net 3.5 作为平台。

我已将此 Xml 数据绑定到数据网格并允许用户修改数据网格。基于某些条件,当用户修改数据网格中的单元格时,我必须在 Xml 中选择一些节点,然后创建新节点并将其添加到内存中的 XmlDocument 中。所以在选择对象后,我使用的是 clone(),这对我来说非常慢!!

更多编辑在这里::

原始XML如下:

<?xml version="1.0" encoding="UTF-8"?>
<grids>   
    <row>
       <value actualvalue="test1" id="0001" valuetype="Constant"/> // i want to make copy of this node whose id = 0001 and make some changes to it
    <value actualvalue="test2" id="0002" valuetype="String"/>
   </row>  
</grids>



然后我想修改节点,转换后的 XML 应该如下: 新节点已添加并且 ids 已重新排序。

<?xml version="1.0" encoding="UTF-8"?>
<grids>   
    <row>
       <value actualvalue="test1" id="0001" valuetype="newConstant"/> 
       <value actualvalue="test1" id="0002" valuetype="Constant"/> 
    <value actualvalue="test2" id="0003" valuetype="String"/>
   </row>  
</grids>

希望我的详细信息足够!!

【问题讨论】:

  • 这个问题与XPath或查询无关。
  • @Dimitre :我添加了更多细节。我会说可能是 .net 中的功能导致我的性能变慢!
  • @Guru-Charan:这可以通过 XSLT 非常有效地完成。请在您的问题中提供一个示例 XML 文档(尽可能少)和想要的结果,并解释如何将源 XML 文档转换为结果。
  • @Dimitre:我在我的问题中添加了详细信息?我的问题现在更清楚了吗?
  • 好问题,+1。请参阅我的答案以获得完整的 XSLT 解决方案。

标签: .net xml xslt


【解决方案1】:

其他具有“细粒度遍历”的 XSLT 解决方案:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:strip-space elements="*"/>
    <xsl:param name="pSearchId" select="1"/>
    <xsl:template match="node()|@*" name="identity">
        <xsl:param name="pIdIncrement" select="0"/>
        <xsl:copy>
            <xsl:apply-templates select="node()[1]|@*">
                <xsl:with-param name="pIdIncrement" select="$pIdIncrement"/>
            </xsl:apply-templates>
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::node()[1]">
            <xsl:with-param name="pIdIncrement" select="$pIdIncrement"/>
        </xsl:apply-templates>
    </xsl:template>
    <xsl:template match="value">
        <xsl:param name="pIdIncrement"/>
        <xsl:if test="@id = $pSearchId">
            <value actualvalue="{@actualvalue}" 
                   id="{@id}" 
                   valuetype="new{@valuetype}"/>
        </xsl:if>
        <xsl:call-template name="identity">
            <xsl:with-param name="pIdIncrement" 
                            select="$pIdIncrement + (@id = $pSearchId)"/>
        </xsl:call-template>
    </xsl:template>
    <xsl:template match="value/@id">
        <xsl:param name="pIdIncrement"/>
        <xsl:attribute name="id">
            <xsl:value-of select="format-number(.+$pIdIncrement,'0000')"/>
        </xsl:attribute>
    </xsl:template>
</xsl:stylesheet>

输出:

<grids>
    <row>
        <value actualvalue="test1" id="0001" valuetype="newConstant"/>
        <value actualvalue="test1" id="0002" valuetype="Constant"/> // i want to make copy of this node whose id = 0001 and make some changes to it
        <value actualvalue="test2" id="0003" valuetype="String"/>
    </row>
</grids>

【讨论】:

  • @Alejandro - [我正在发布与@Robert 相同的评论] 感谢您的回答。我对 XSLT 的了解较少,因此目前很难理解您的解决方案 :) 但我已经开始学习它,我会尽快实施您的解决方案,并让您知道它是否解决了我的问题 :)
  • @Guru Charan:你很高兴。
【解决方案2】:

我怀疑这里的罪魁祸首是这样的:

我已将此 Xml 数据绑定到数据网格并允许用户修改数据网格。

数据绑定会影响性能。当对象绑定到 UI 时,对该对象的所有更改都会动态反映在 UI 更改中。如果您对对象进行了多次更新,并且这些更改中的每一个都在您进行更新时传播到 UI,那么您将 UI 组件重新格式化和呈现的计算成本插入到 XML 更新的中间。

如果您禁用绑定,执行更新,然后在更新完成后重新启用绑定,您所描述的性能问题很可能会变得微不足道。

【讨论】:

  • 感谢您的信息!但我想知道如何禁用绑定到 XML 的 DataGrid 的绑定,然后重新启用绑定?你能不能多解释一下:)
  • 这完全取决于您如何进行绑定。我已经有一段时间没有使用BindingSource 对象了(我已经转向 WPF),但我记得它上面有一个属性,您可以设置它来执行此操作。您也可以在进行此更新时简单地禁用DataGrid;这可能会奏效。
【解决方案3】:

这种转变:

<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:param name="pinsertBefore" select="1"/>
 <xsl:param name="pnewActualvalue" select="'test1'"/>
 <xsl:param name="pnewValueType"
      select="'newConstant'"/>

 <xsl:template match="node()|@*" name="identity">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="value">
  <xsl:choose>
   <xsl:when test=
    "(not(@id >= $pinsertBefore)
    and
      not(following-sibling::value[1]/@id = $pinsertBefore)
      )
    ">
    <xsl:call-template name="identity"/>
   </xsl:when>

   <xsl:when test=
    "not(@id >= $pinsertBefore)
    and
     following-sibling::value[1]/@id = $pinsertBefore
    ">
     <xsl:call-template name="identity"/>

     <value actualvalue="{$pnewActualvalue}"
            id="{$pinsertBefore}"
            valuetype="{$pnewValueType}"/>
   </xsl:when>

   <xsl:when test=
    "@id = $pinsertBefore
    and
     not(preceding-sibling::value[1])
    ">
     <value actualvalue="{$pnewActualvalue}"
            id="{$pinsertBefore}"
            valuetype="{$pnewValueType}"/>

     <xsl:apply-templates select="." mode="increment"/>
   </xsl:when>
   <xsl:otherwise>
     <xsl:apply-templates select="." mode="increment"/>
   </xsl:otherwise>
  </xsl:choose>
 </xsl:template>

 <xsl:template match="node()|@*" mode="increment">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*" mode="increment"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="value/@id" mode="increment">
  <xsl:attribute name="id">
    <xsl:value-of select=". +1"/>
  </xsl:attribute>
 </xsl:template>
</xsl:stylesheet>

应用于提供的 XML 文档时

<grids>
    <row>
       <value actualvalue="test1" id="0001"
       valuetype="Constant"/>
       <!-- i want to make copy of this node
       whose id = 0001 and make some changes to it
       -->
    <value actualvalue="test2" id="0002"
           valuetype="String"/>
   </row>
</grids>

产生想要的正确结果

<grids>
   <row>
      <value actualvalue="test1" id="1" valuetype="newConstant"/>
      <value actualvalue="test1" id="2" valuetype="Constant"/><!-- i want to make copy of this node
       whose id = 0001 and make some changes to it
       -->
      <value actualvalue="test2" id="3" valuetype="String"/>
   </row>
</grids>

请注意

  1. identity 模板“按原样”复制每个节点。

  2. 匹配value的模板区分了四种情况,其中一种是原样复制节点,另一种是复制节点并增加其id属性,以及在其中两种情况下,节点被复制(增加或不增加其id 属性)并创建新的value 元素。

【讨论】:

  • 感谢您的回答。我对 XSLT 的了解较少,因此目前很难理解您的解决方案 :) 但我已经开始学习它,我会尽快实施您的解决方案,并让您知道它是否解决了我的问题 :)
【解决方案4】:

如果 Clone 方法有问题,我不确定这个问题与 XPath 有什么关系。请先告诉我们您使用的语言和平台。我从 XmlNode 和 XmlDocument 怀疑您正在使用 .NET 框架,但您并没有真正告诉我们。 至于替代方案,更改/转换/插入节点也可以使用 XSLT 完成(尽管您不会以这种方式对现有对象进行更改,而是创建一个新结果)。我不知道这是否表现更好,您需要对其进行测量才能准确知道。

【讨论】:

  • 我已经为这个问题添加了更多细节。您提到了“可以使用 XSLT 插入元素”您能详细说明一下吗?因为我想对加载到内存中的现有 XmlDocument 对象进行更改,并且在所有更改之后将 Xml 保存在不同的文件中。
猜你喜欢
  • 2018-11-14
  • 2014-05-04
  • 1970-01-01
  • 2023-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-02
  • 2020-01-10
相关资源
最近更新 更多