开发者

XmlNode clone() very slow in XPath queries in XML

I have a requirement where in there is a big XML document. I have to select lot of nodes using XPath from the document based on some condition. Then after I select the XmlNodes, I have to add new properties to the selected nodes and insert it back in many places in XmlDocument.

I found out that when I modify the selected XmlNode, the actual XmlDocument is also getting modified. So I thought of using xmlNode.Clone() method on the entire list of selected XmlNodes. But it is really very very slow. I mean is there a better way to do it?? Or is clone really very slow??

By the way, I am using XmlDocument to load the Xml document.

Edits HERE :::

I am adding more details to my question. I am using C# language and .net 3.5 as platform.

I have databound this Xml to a datagrid and allowing the user to modify the datagrid. Based on some condition, when the user modifies a cell in a datagrid, I have to select some nodes in Xml and then create new nodes and add it to the XmlDocument that is in memory. So after selecting the objects, I was using clone() which is very very slow for me!!

More Edits HERE::

The original XML is as follows:

<?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>

Then i want to modify the n开发者_StackOverflow社区ode and the converted XML should be as follows: New node has been added and ids have been reordered.

<?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>

Hope my details are sufficient!!


Other XSLT solution with "fine grained traversal":

<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>

Output:

<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>


I'd suspect that the culprit here is this:

I have databound this Xml to a datagrid and allowing the user to modify the datagrid.

Data binding kills performance. When an object is bound to the UI, all changes to that object are dynamically reflected in changes to the UI. If you're making many updates to the object, and each of those changes is being propagated to the UI as you make them, you're inserting the computational cost of the UI components' reformatting and rendering into the middle of your XML update.

If you disable binding, perform the update, and then re-enable binding after the update's done, it's quite likely that the performance issues you're describing will diminish into insignificance.


This transformation:

<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>

when applied on the provided XML document:

<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>

produces the wanted, correct result:

<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>

Do note:

  1. The identity template copies every node "as-is".

  2. The template matching value distinguishes four cases, in one of them the node is copied as is, in another the node is copied and its id attribute is incremented, and in two of the cases the node is copied (with or without incrementing its id attribute) and the new value element is created.


I am not sure what the question has to do with XPath if the Clone method is the problem. Please first tell us what language and platform you use. I suspect from XmlNode and XmlDocument that you are using the .NET framework but you haven't really told us. As for alternatives, changing/transforming/inserting nodes can also be done with XSLT (although you don't make changes on an existing object that way, you create a new result). Whether that performs better I don't know, you would need to measure that to know exactly.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜