基于属性的 Unpivot xml 文档

发布于 2024-07-05 16:02:45 字数 617 浏览 9 评论 0原文

我有一个简单的 xml 文档,如下所示。 我需要编写一个 XSLT 转换,基本上根据某些属性“反转”此文档。

<?xml version="1.0" encoding="utf-8" ?>
<root xmlns:z="foo">
    <z:row A="1" X="2" Y="n1" Z="500"/>
    <z:row A="2" X="5" Y="n2" Z="1500"/>
</root>

这就是我期望的输出 -

<?xml version="1.0" encoding="utf-8" ?>
<root xmlns:z="foo">
    <z:row A="1" X="2"  />
    <z:row A="1" Y="n1" />
    <z:row A="1" Z="500"/>
    <z:row A="2" X="5" />
    <z:row A="2" Y="n2"/>
    <z:row A="2" Z="1500"/>
</root>

感谢您的帮助。

I have a simple xml document that looks like the following snippet. I need to write a XSLT transform that basically 'unpivots' this document based on some of the attributes.

<?xml version="1.0" encoding="utf-8" ?>
<root xmlns:z="foo">
    <z:row A="1" X="2" Y="n1" Z="500"/>
    <z:row A="2" X="5" Y="n2" Z="1500"/>
</root>

This is what I expect the output to be -

<?xml version="1.0" encoding="utf-8" ?>
<root xmlns:z="foo">
    <z:row A="1" X="2"  />
    <z:row A="1" Y="n1" />
    <z:row A="1" Z="500"/>
    <z:row A="2" X="5" />
    <z:row A="2" Y="n2"/>
    <z:row A="2" Z="1500"/>
</root>

Appreciate your help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

我不吻晚风 2024-07-12 16:02:45

这是一种比较暴力的方法:

<xsl:template match="z:row">
    <xsl:element name="z:row">
        <xsl:attribute name="A">
            <xsl:value-of select="@A"/>
        </xsl:attribute>
        <xsl:attribute name="X">
            <xsl:value-of select="@X"/>
        </xsl:attribute>
    </xsl:element>
    <xsl:element name="z:row">
        <xsl:attribute name="A">
            <xsl:value-of select="@A"/>
        </xsl:attribute>
        <xsl:attribute name="Y">
            <xsl:value-of select="@Y"/>
        </xsl:attribute>
    </xsl:element>
    <xsl:element name="z:row">
        <xsl:attribute name="A">
            <xsl:value-of select="@A"/>
        </xsl:attribute>
        <xsl:attribute name="Z">
            <xsl:value-of select="@Z"/>
        </xsl:attribute>
    </xsl:element>
</xsl:template>


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

Here is a bit of a brute force way:

<xsl:template match="z:row">
    <xsl:element name="z:row">
        <xsl:attribute name="A">
            <xsl:value-of select="@A"/>
        </xsl:attribute>
        <xsl:attribute name="X">
            <xsl:value-of select="@X"/>
        </xsl:attribute>
    </xsl:element>
    <xsl:element name="z:row">
        <xsl:attribute name="A">
            <xsl:value-of select="@A"/>
        </xsl:attribute>
        <xsl:attribute name="Y">
            <xsl:value-of select="@Y"/>
        </xsl:attribute>
    </xsl:element>
    <xsl:element name="z:row">
        <xsl:attribute name="A">
            <xsl:value-of select="@A"/>
        </xsl:attribute>
        <xsl:attribute name="Z">
            <xsl:value-of select="@Z"/>
        </xsl:attribute>
    </xsl:element>
</xsl:template>


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

这个俗人 2024-07-12 16:02:45
<xsl:template match="row">
    <row A="{$A}" X="{$X}" />
    <row A="{$A}" Y="{$Y}" />
    <row A="{$A}" Z="{$Z}" />
</xsl:template>

加上明显的样板。

<xsl:template match="row">
    <row A="{$A}" X="{$X}" />
    <row A="{$A}" Y="{$Y}" />
    <row A="{$A}" Z="{$Z}" />
</xsl:template>

Plus obvious boilerplate.

半暖夏伤 2024-07-12 16:02:45

这更复杂,但也更通用:

<xsl:template match="z:row">
    <xsl:variable name="attr" select="@A"/>
    <xsl:for-each select="@*[(local-name() != 'A')]">
        <xsl:element name="z:row">
            <xsl:copy-of select="$attr"/>
            <xsl:attribute name="{name()}"><xsl:value-of select="."/></xsl:attribute>
        </xsl:element>
    </xsl:for-each>
</xsl:template>

This is more complex but also more generic:

<xsl:template match="z:row">
    <xsl:variable name="attr" select="@A"/>
    <xsl:for-each select="@*[(local-name() != 'A')]">
        <xsl:element name="z:row">
            <xsl:copy-of select="$attr"/>
            <xsl:attribute name="{name()}"><xsl:value-of select="."/></xsl:attribute>
        </xsl:element>
    </xsl:for-each>
</xsl:template>
手心的海 2024-07-12 16:02:45

这是您需要的完整样式表(因为命名空间很重要):

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:z="foo">

<xsl:template match="root">
  <root>
    <xsl:apply-templates />
  </root>
</xsl:template>

<xsl:template match="z:row">
  <xsl:variable name="A" select="@A" />
  <xsl:for-each select="@*[local-name() != 'A']">
    <z:row A="{$A}">
      <xsl:attribute name="{local-name()}">
        <xsl:value-of select="." />
      </xsl:attribute>
    </z:row>
  </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

我更喜欢使用文字结果元素(例如 )而不是 和属性值模板(属性值中的 {}),因为这样可以使代码更短并且更容易查看您生成的结果文档的结构。 其他人更喜欢 因为这样一切都是 XSLT 指令。

如果您使用的是 XSLT 2.0,有一些语法细节会有所帮助,即 XPath 中的 except 运算符以及直接在 上使用 select 属性的能力>:

<xsl:stylesheet version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs"
  xmlns:z="foo">

<xsl:template match="root">
  <root>
    <xsl:apply-templates />
  </root>
</xsl:template>

<xsl:template match="z:row">
  <xsl:variable name="A" as="xs:string" select="@A" />
  <xsl:for-each select="@* except @A">
    <z:row A="{$A}">
      <xsl:attribute name="{local-name()}" select="." />
    </z:row>
  </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

Here's the full stylesheet you need (since the namespaces are important):

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:z="foo">

<xsl:template match="root">
  <root>
    <xsl:apply-templates />
  </root>
</xsl:template>

<xsl:template match="z:row">
  <xsl:variable name="A" select="@A" />
  <xsl:for-each select="@*[local-name() != 'A']">
    <z:row A="{$A}">
      <xsl:attribute name="{local-name()}">
        <xsl:value-of select="." />
      </xsl:attribute>
    </z:row>
  </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

I much prefer using literal result elements (eg <z:row>) rather than <xsl:element> and attribute value templates (those {}s in attribute values) rather than <xsl:attribute> where possible as it makes the code shorter and makes it easier to see the structure of the result document that you're generating. Others prefer <xsl:element> and <xsl:attribute> because then everything is an XSLT instruction.

If you're using XSLT 2.0, there are a couple of syntactic niceties that help, namely the except operator in XPath and the ability to use a select attribute directly on <xsl:attribute>:

<xsl:stylesheet version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="xs"
  xmlns:z="foo">

<xsl:template match="root">
  <root>
    <xsl:apply-templates />
  </root>
</xsl:template>

<xsl:template match="z:row">
  <xsl:variable name="A" as="xs:string" select="@A" />
  <xsl:for-each select="@* except @A">
    <z:row A="{$A}">
      <xsl:attribute name="{local-name()}" select="." />
    </z:row>
  </xsl:for-each>
</xsl:template>

</xsl:stylesheet>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文