Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/427.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 将XML格式的Web数据传递到SQL Server数据库的合理方法_Javascript_Sql Server_Xml_Asp Classic - Fatal编程技术网

Javascript 将XML格式的Web数据传递到SQL Server数据库的合理方法

Javascript 将XML格式的Web数据传递到SQL Server数据库的合理方法,javascript,sql-server,xml,asp-classic,Javascript,Sql Server,Xml,Asp Classic,在探索了几种将web数据传递到数据库进行更新的不同方法之后,我想知道XML是否是一种好的策略。数据库当前为SQL 2000。几个月后,它将转移到SQL 2005,如果需要,我将能够更改内容,但我现在需要一个SQL 2000解决方案 首先,所讨论的数据库使用。我知道这种类型的数据库通常是非常不受欢迎的,所以就这个问题而言,请接受这种情况不会改变 当前的更新方法让web服务器将值(首先转换为正确的基础类型,然后转换为sql_变量)插入临时表。然后运行一个存储过程,该过程期望临时表存在,并根据需要负责

在探索了几种将web数据传递到数据库进行更新的不同方法之后,我想知道XML是否是一种好的策略。数据库当前为SQL 2000。几个月后,它将转移到SQL 2005,如果需要,我将能够更改内容,但我现在需要一个SQL 2000解决方案

首先,所讨论的数据库使用。我知道这种类型的数据库通常是非常不受欢迎的,所以就这个问题而言,请接受这种情况不会改变

当前的更新方法让web服务器将值(首先转换为正确的基础类型,然后转换为sql_变量)插入临时表。然后运行一个存储过程,该过程期望临时表存在,并根据需要负责更新、插入或删除内容

到目前为止,一次只需要更新一个元素。但现在,需要能够一次编辑多个元素,还需要支持分层元素,每个元素都有自己的属性列表。下面是我手工键入的一些XML示例,以演示我的想法

请注意,在该数据库中,实体是元素,ID为0表示“创建”即插入新项

<Elements>
  <Element ID="1234">
    <Attr ID="221">Value</Attr>
    <Attr ID="225">287</Attr>
    <Attr ID="234">
      <Element ID="99825">
        <Attr ID="7">Value1</Attr>
        <Attr ID="8">Value2</Attr>
        <Attr ID="9" Action="delete" />
      </Element>
      <Element ID="99826" Action="delete" />
      <Element ID="0" Type="24">
        <Attr ID="7">Value4</Attr>
        <Attr ID="8">Value5</Attr>
        <Attr ID="9">Value6</Attr>
      </Element>
      <Element ID="0" Type="24">
        <Attr ID="7">Value7</Attr>
        <Attr ID="8">Value8</Attr>
        <Attr ID="9">Value9</Attr>
      </Element>
    </Attr>
    <Rel ID="3827" Action="delete" />
    <Rel ID="2284" Role="parent">
      <Element ID="3827" />
      <Element ID="3829" />
      <Attr ID="665">1</Attr>
    </Rel>
    <Rel ID="0" Type="23" Role="child">
      <Element ID="3830" />
      <Attr ID="67"
    </Rel>
  </Element>
  <Element ID="0" Type="87">
    <Attr ID="221">Value</Attr>
    <Attr ID="225">569</Attr>
    <Attr ID="234">
      <Element ID="0" Type="24">
        <Attr ID="7">Value10</Attr>
        <Attr ID="8">Value11</Attr>
        <Attr ID="9">Value12</Attr>
      </Element>
    </Attr>
  </Element>
  <Element ID="1235" Action="delete" />
</Elements>
示例:模板输入名称_a678变为n1_a678(一个新元素,页面上的第一个元素,属性678)。此新元素的所有属性都使用相同的前缀n1进行标记。下一个新项目将是n2,依此类推。创建了一些隐藏的表单输入:

n1_t,value是要创建的元素的elementtype n1_p,value是元素的父id(如果是关系) n1_c,value是元素的子id(如果是关系)

  • 删除元素

    以e12345_t的形式创建一个隐藏输入,其值设置为0。显示该属性值的现有控件被禁用,因此它们不包括在表单post中。因此,“将类型设置为0”被视为删除

  • 使用此方案,页面上的每个项目都有一个唯一的名称,可以正确区分,并且每个操作都可以正确表示

    发布表单时,下面是构建所用两个记录集之一的示例(经典ASP代码):

    这是值的记录集,另一个是元素本身的记录集

    我一步一步地浏览发布的表单,对于元素记录集,使用脚本.字典填充具有我需要的属性的自定义类的实例,这样我就可以逐段添加值,因为它们并不总是按顺序排列的。新元素被添加为负数,以区别于常规元素(而不是要求单独的列来指示它是新的还是针对现有元素)。我使用正则表达式分离表单键:“^(e | n)([0-9]{1,10})(a | p | t | c)([0-9]{0,10})$”

    然后,添加一个属性如下所示

    Data.AddNew
    ElementID.Value = DataID
    AttrID.Value = Integerize(Matches(0).SubMatches(3))
    AttrValue.Value = Request.Form(Key)
    Data.Update
    
    ElementID、AttrID和AttrValue是对记录集字段的引用。这种方法比每次使用Data.Fields(“ElementID”)值要快得多

    我在元素更新字典中循环,忽略所有没有正确信息的元素,将好的元素添加到记录集中

    然后调用数据更新存储过程,如下所示:

    Set Cmd = Server.CreateObject("ADODB.Command")
    With Cmd
       Set .ActiveConnection = MyDBConn
       .CommandType = adCmdStoredProc
       .CommandText = "DataPost"
       .Prepared = False
       .Parameters.Append .CreateParameter("@ElementMetadata", adLongVarWChar, adParamInput, 2147483647, XMLFromRecordset(Element))
       .Parameters.Append .CreateParameter("@ElementData", adLongVarWChar, adParamInput, 2147483647, XMLFromRecordset(Data))
    End With
    Result.Open Cmd ' previously created recordset object with options set
    
    下面是执行xml转换的函数:

    Private Function XMLFromRecordset(Recordset)
       Dim Stream
       Set Stream = Server.CreateObject("ADODB.Stream")
       Stream.Open
       Recordset.Save Stream, adPersistXML
       Stream.Position = 0
       XMLFromRecordset = Stream.ReadText
    End Function
    
    为了防止web页面需要知道,SP返回任何新元素的记录集,显示它们的页面值和创建的值(例如,我可以看到n1现在是e12346)

    下面是存储过程中的一些关键片段。请注意,目前这是SQL 2000,不过我很快就能切换到2005:

    CREATE PROCEDURE [dbo].[DataPost]
       @ElementMetaData ntext,
       @ElementData ntext
    AS
    DECLARE @hdoc int
    
    --- snip ---
    
    EXEC sp_xml_preparedocument @hdoc OUTPUT, @ElementMetaData, '<xml xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema" />'
    INSERT #ElementMetadata (ElementID, ElementTypeID, ElementID1, ElementID2)
    SELECT *
    FROM
       OPENXML(@hdoc, '/xml/rs:data/rs:insert/z:row', 0)
       WITH (
          ElementID int,
          ElementTypeID int,
          ElementID1 int,
          ElementID2 int
       )
    ORDER BY ElementID -- orders negative items (new elements) first so they begin counting at 1 for later ID calculation
    
    EXEC sp_xml_removedocument @hdoc
    
    --- snip ---
    
    UPDATE E
    SET E.ElementTypeID = M.ElementTypeID
    FROM
       Element E
       INNER JOIN #ElementMetadata M ON E.ElementID = M.ElementID
    WHERE
       E.ElementID >= 1
       AND M.ElementTypeID >= 1
    
    创建过程[dbo].[DataPost]
    @ElementText,
    @元素数据文本
    作为
    声明@hdoc int
    ---剪断---
    EXEC sp_xml_preparedocument@hdoc OUTPUT,@ElementMetaData,''
    插入#ElementMetadata(ElementID、ElementTypeID、ElementID1、ElementID2)
    挑选*
    从…起
    OPENXML(@hdoc,'/xml/rs:data/rs:insert/z:row',0)
    与(
    元素ID int,
    ElementTypeID int,
    ElementID1 int,
    ElementID2 int
    )
    ORDER BY ElementID——首先对负项(新元素)进行排序,以便它们从1开始计数,以便以后计算ID
    EXEC sp_xml_removedocument@hdoc
    ---剪断---
    更新E
    设置E.ElementTypeID=M.ElementTypeID
    从…起
    元素E
    E.ElementID=M.ElementID上的内部联接#ElementMetadata M
    哪里
    E.ElementID>=1
    而M.ElementTypeID>=1
    
    以下查询不会将负新元素ID与新插入的ID进行关联:

    UPDATE #ElementMetadata -- Correlate the new ElementIDs with the input rows
    SET NewElementID = Scope_Identity() - @@RowCount + DataID
    WHERE ElementID < 0
    
    UPDATE#ElementMetadata——将新的elementid与输入行关联起来
    SET-NewElementID=Scope_Identity()-@@RowCount+DataID
    其中ElementID<0
    
    其他基于集合的查询执行所有其他工作,包括验证属性是否被允许、是否为正确的数据类型以及插入、更新和删除元素和属性

    我希望这篇简短的总结有一天对其他人有用!将ADO记录集转换为XML流对我来说是一个巨大的赢家,因为它节省了各种时间,并且已经定义了一个名称空间和模式,可以正确地得出结果


    使用带有2个输入的更平坦的XML格式也比坚持将所有内容都放在一个XML流中的理想方式要容易得多。

    我看不出有任何理由不在SQL Server 2005中使用XML列,也没有理由不通过存储过程来完成所有工作

    您可能没有时间抽象数据访问以隐藏数据模型的丑陋,所以为什么不使用XML按原样访问它呢?您可以在SQLServer中使用XQuery进行更新、查询等

    现在我想起来了,您仍然可以在ASP页面和数据库之间放置一层抽象。这将允许您在将来使用XSLT将XML的结构转换为一种格式,这种格式在d语言中性能更好
    CREATE PROCEDURE [dbo].[DataPost]
       @ElementMetaData ntext,
       @ElementData ntext
    AS
    DECLARE @hdoc int
    
    --- snip ---
    
    EXEC sp_xml_preparedocument @hdoc OUTPUT, @ElementMetaData, '<xml xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema" />'
    INSERT #ElementMetadata (ElementID, ElementTypeID, ElementID1, ElementID2)
    SELECT *
    FROM
       OPENXML(@hdoc, '/xml/rs:data/rs:insert/z:row', 0)
       WITH (
          ElementID int,
          ElementTypeID int,
          ElementID1 int,
          ElementID2 int
       )
    ORDER BY ElementID -- orders negative items (new elements) first so they begin counting at 1 for later ID calculation
    
    EXEC sp_xml_removedocument @hdoc
    
    --- snip ---
    
    UPDATE E
    SET E.ElementTypeID = M.ElementTypeID
    FROM
       Element E
       INNER JOIN #ElementMetadata M ON E.ElementID = M.ElementID
    WHERE
       E.ElementID >= 1
       AND M.ElementTypeID >= 1
    
    UPDATE #ElementMetadata -- Correlate the new ElementIDs with the input rows
    SET NewElementID = Scope_Identity() - @@RowCount + DataID
    WHERE ElementID < 0
    
    select x.value(N'@ID', N'int') as ID,
      x.value(N'.', N'varchar(max)') as [Value]
    from  @x.nodes('//Element[not(@Action="delete") and not (@ID=0)]/Attr') t(x)
    
    select x.value(N'@ID', N'int') as ID,
      x.value(N'.', N'varchar(max)') as [Value]
    from  @x.nodes('//Element[@ID=0]/Attr') t(x);
    
    select x.value(N'@ID', N'int') as ID
    from  @x.nodes('//Element[@Action="delete"]') t(x);