【问题标题】:How to create xml from another xml meta data?如何从另一个 xml 元数据创建 xml?
【发布时间】:2009-04-06 14:02:50
【问题描述】:

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

我需要使用 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

【问题讨论】:

  • 源 XML 只是格式的 XML。它绝对不符合 XML 的“精神”,因此任何使用 XSL 的解决方案充其量都是 hackish。如果您对源格式有任何控制权,我强烈建议您将其更改为分层格式。
  • 解决方案中没有任何“hackish”。 XSLT 可用于为许多“非传统”或看似“不可能解决”的问题提供优雅的解决方案。

标签: c# .net xml xslt


【解决方案1】:

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

<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. 我们将模板应用于每个第 N 个 ax21:resultData 元素,其中 N mod $vNumCols = 1 。每个这样的元素都开始一个新的item

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

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

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

【讨论】:

  • 谢谢迪米特!!我不确定这是否可以通过 XSLT 解决,我只是在这里发布它以获得您对这个问题的意见。再次感谢。
  • 另一方面,xml 结构在我发布后发生了变化,它更正确,并且具有 Marc 建议的索引。您的上述答案将帮助我为新的模板创建模板。再次感谢。
  • @gk 欢迎您! :) 有许多问题似乎比这更“难”,可以在 XSLT 中以一种优雅的方式解决。在很短的时间内,我已经解决了 60 个 Project Euler 问题,并且在 XSLT 中实现了其中任何一个问题的解决方案(无法用钢笔和铅笔完成)。
  • +1 - 很好的答案,很好地展示了 XSLT 可以做什么 - 干得好!
【解决方案2】:

如果不是不可能的话,要正确可靠地完成这将非常困难。

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

如果至少有一个额外的属性,比如等等,那将是一个不同的故事——这样人们就可以以某种方式将它们联系在一起。

你有没有机会“按摩”一下原始数据?否则,我可能会说您必须在 C# 中加载它并对其进行解析并进行大量手动处理才能获得所需的内容。

马克

【讨论】:

  • 一点都不难!当然,绝对有可能。 XSLT 是一种功能强大的语言,可为此类问题提供优雅的解决方案。一个人只需要思考:)
  • 我也有类似的想法,正在等待 Dimitre 的回应。无论如何,我已经与其他团队合作以使 xml 具有更有意义的结构。
  • 伙计们,如果你想看到一些真正具有挑战性的问题的优雅 XSLT 解决方案,请看这里:stackoverflow.com/questions/693596/elegant-examples-of-xslt/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多