如何从另一个xml元数据创建xml?

时间:2009-04-06 14:02:51

标签: c# .net xml xslt

我不确定标题是否清楚地解释了我的问题,我会尽量包含尽可能多的细节。

我需要使用Xslt 1将xml转换为格式正确的格式,以便我可以将其反序列化为.net类型。

源XML

            <ax21:result type="test.ws.Result">
                <ax21:columnNames>fileName</ax21:columnNames>
                <ax21:columnNames>lockedState</ax21:columnNames>
                <ax21:columnNames>currentLockOwner</ax21:columnNames>
                <ax21:columnNames>UUID</ax21:columnNames>
                <ax21:resultData>Test1.doc</ax21:resultData>
                <ax21:resultData>true</ax21:resultData>
                <ax21:resultData>analyst</ax21:resultData>
                <ax21:resultData>f48f0450-9ecc-4a44-b063-898d9d72d112</ax21:resultData>
                <ax21:resultData>Test2.doc</ax21:resultData>
                <ax21:resultData>false</ax21:resultData>
                <ax21:resultData/>
                <ax21:resultData>f48f0450-9ecc-4a44-b063-898d9d72d112</ax21:resultData>
                <ax21:resultData>Test3.doc</ax21:resultData>
                <ax21:resultData>true</ax21:resultData>
                <ax21:resultData>analyst</ax21:resultData>
                <ax21:resultData>f48f0450-9ecc-4a44-b063-898d9d72d112</ax21:resultData>
                <ax21:resultData>Test4.doc</ax21:resultData>
                <ax21:resultData>false</ax21:resultData>
                <ax21:resultData/>
                <ax21:resultData>f48f0450-9ecc-4a44-b063-898d9d72d112</ax21:resultData>
            </ax21:result>

目标XML

<result>
    <item>
        <fileName>Test1.doc</fileName>
        <lockedState>true</lockedState>
        <currentLockOwner>analyst</currentLockOwner>
        <UUID>f48f0450-9ecc-4a44-b063-898d9d72d112</UUID>
    </item>
    <item>
        <fileName>Test2.doc</fileName>
        <lockedState>true</lockedState>
        <currentLockOwner>analyst</currentLockOwner>
        <UUID>f48f0450-9ecc-4a44-b063-898d9d72d112</UUID>
    </item>
    <item>
        <fileName>Test2.doc</fileName>
        <lockedState>true</lockedState>
        <currentLockOwner>analyst</currentLockOwner>
        <UUID>f48f0450-9ecc-4a44-b063-898d9d72d112</UUID>
    </item>
</result>

可以使用xslt完成吗?如果是,请发布链接或示例xslt供我试用。

我正在使用.net 2.0,c#,XSLT 1.0

2 个答案:

答案 0 :(得分:3)

这是一个相当简短的解决方案

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ax21="my:ax21" exclude-result-prefixes="ax21"
 >
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <xsl:variable name="vCols" select="/*/ax21:columnNames"/>
  <xsl:variable name="vNumCols" select="count($vCols)"/>

    <xsl:template match="ax21:result">
        <result>
          <xsl:apply-templates select=
           "ax21:resultData[position() mod $vNumCols = 1]"
           />
        </result>
    </xsl:template>

    <xsl:template match="ax21:resultData">
      <item>
        <xsl:apply-templates mode="create" select=
         "(.|following-sibling::ax21:resultData)
                               [not(position() > $vNumCols) ]
         "/>
      </item>
    </xsl:template>

    <xsl:template match="ax21:resultData" mode="create">
      <xsl:variable name="vPos" select="position()"/>
    <xsl:element name="{$vCols[$vPos]}">
          <xsl:value-of select="."/>
          <xsl:if test="not(text())">
            <xsl:value-of select=
             "(.| preceding-sibling::ax21:resultData)
                         [position() mod $vNumCols = $vPos]
                            [text()]
                                  [last()]
             "/>
          </xsl:if>
    </xsl:element>
    </xsl:template>
</xsl:stylesheet>

将此转换应用于以下XML文档

<ax21:result type="test.ws.Result"
 xmlns:ax21="my:ax21"
>
    <ax21:columnNames>fileName</ax21:columnNames>
    <ax21:columnNames>lockedState</ax21:columnNames>
    <ax21:columnNames>currentLockOwner</ax21:columnNames>
    <ax21:columnNames>UUID</ax21:columnNames>
    <ax21:resultData>Test1.doc</ax21:resultData>
    <ax21:resultData>true</ax21:resultData>
    <ax21:resultData>analyst</ax21:resultData>
    <ax21:resultData>f48f0450-9ecc-4a44-b063-898d9d72d112</ax21:resultData>
    <ax21:resultData>Test2.doc</ax21:resultData>
    <ax21:resultData>false</ax21:resultData>
    <ax21:resultData/>
    <ax21:resultData>f48f0450-9ecc-4a44-b063-898d9d72d112</ax21:resultData>
    <ax21:resultData>Test3.doc</ax21:resultData>
    <ax21:resultData>true</ax21:resultData>
    <ax21:resultData>analyst</ax21:resultData>
    <ax21:resultData>f48f0450-9ecc-4a44-b063-898d9d72d112</ax21:resultData>
    <ax21:resultData>Test4.doc</ax21:resultData>
    <ax21:resultData>false</ax21:resultData>
    <ax21:resultData/>
    <ax21:resultData>f48f0450-9ecc-4a44-b063-898d9d72d112</ax21:resultData>
</ax21:result>

生成了想要的结果

<result>
   <item>
      <fileName>Test1.doc</fileName>
      <lockedState>true</lockedState>
      <currentLockOwner>analyst</currentLockOwner>
      <UUID>f48f0450-9ecc-4a44-b063-898d9d72d112</UUID>
   </item>
   <item>
      <fileName>Test2.doc</fileName>
      <lockedState>false</lockedState>
      <currentLockOwner>analyst</currentLockOwner>
      <UUID>f48f0450-9ecc-4a44-b063-898d9d72d112</UUID>
   </item>
   <item>
      <fileName>Test3.doc</fileName>
      <lockedState>true</lockedState>
      <currentLockOwner>analyst</currentLockOwner>
      <UUID>f48f0450-9ecc-4a44-b063-898d9d72d112</UUID>
   </item>
   <item>
      <fileName>Test4.doc</fileName>
      <lockedState>false</lockedState>
      <currentLockOwner>analyst</currentLockOwner>
      <UUID>f48f0450-9ecc-4a44-b063-898d9d72d112</UUID>
   </item>
</result>

<强>解释

  1. 为方便起见,列名称及其编号收集在全局变量$vCols$vNumCols中。

  2. 我们正在将模板应用于每个第ax21:resultData个元素,其中N mod $vNumCols = 1。每个这样的元素都会启动一个新的item

  3. ax21:resultData中第一个item元素与“无模式”中的模板匹配。这只是创建包装item元素,并以ax21:resultData模式应用于所有当前的$ vNumCols "create"元素另一个模板。

  4. "create"模式下的模板只创建一个元素,其名称是$vCols中第n个元素的值,其中nposition()正在应用模板的current()节点。

  5. 最后,如果没有提供任何值,我们会(按向后的顺序)获得相同类型元素的最新非空值。

答案 1 :(得分:0)

如果不是不可能的话,那将是非常艰难的,以便正确可靠地完成。

问题是:在许多人和节点上没有关于他们的类型/位置的索引或类型的指示 - 你必须或多或少地猜测......

如果至少有一个额外的属性,例如等等,这将是一个不同的故事 - 这样一来,人们可能会以某种方式将这些属性联系在一起。

有没有机会你可以“按摩”原始数据?否则,我可能会说你必须在C#中加载它并解析它并进行大量的手动处理以获得你想要的东西。

马克