XSLT:没有属​​性且没有子元素的元素转换为父属性 [英] XSLT: element that has no attributes and no children transform to parent attribute

查看:25
本文介绍了XSLT:没有属​​性且没有子元素的元素转换为父属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定 .xml 文件的结构、名称、值未知.

The structure, names, values of the given .xml files is unknown.

对于每个具有简单结构的非根元素(没有子节点,没有属性,但有文本并且不为空)将其转换为父属性.

For every not-root element that has simple structure(has no child-nodes, has no attributes, BUT has text and is not empty) transform it into parent's attribute.

我有 .xml 文件:

I have .xml file:

<list>
   <worker>
      <name atr="ss">val1</name>
   </worker>
   <worker>
      <make1>val2</make1>
   </worker>
   <worker>
      <name>
        <make2>val3</make2>
      </name>
   </worker>
   <worker>
      <name>
        <doo atr="ss1">val4</doo>
        <make3></make3>
      </name>
   </worker>
</list>

我想得到这个:

<list>
   <worker>
      <name atr="ss">val1</name>
   </worker>
   <worker make1="val2"/>
   <worker>
      <name make2="val3"/>
   </worker>
   <worker>
      <name>
        <doo atr="ss1">val4</doo>
        <make3/>
      </name>
   </worker>
</list>

这是我现在的 .xsl(无法正常工作):

Here is my .xsl for now (doesn't work correctly):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output indent="yes" method="xml"/>
    <xsl:template match="@*|node()">
      <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
    </xsl:template>
    <xsl:template match="//*[not(*|@*)]">
        <xsl:copy>
            <xsl:attribute name="{name()}">
                <xsl:value-of select="text()"/>
            </xsl:attribute>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

推荐答案

你的代码

您有两个模板:

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

<xsl:template match="*[not(*) and not(@*)]">
    <xsl:copy>
        <xsl:attribute name="{name()}">
            <xsl:value-of select="text()"/>
        </xsl:attribute>
    </xsl:copy>
</xsl:template>

你的输出产生 而不是 .这是因为外部 元素由顶部模板处理,顶部模板只是复制它,然后传递子元素,由底部模板处理.

Your output produces <worker><make1 make1="val2"/></worker> instead of <worker make1="val2"/>. This is because the outer <worker> element is processed by the top template, which just copies it and then passes the child along, which gets processed by the bottom template.

以下对我有用,并且只使用一个模板.

The following works for me, and uses only one template.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

    <xsl:output indent="yes"/>

    <xsl:strip-space elements="*"/>

    <xsl:template match="*">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <!-- Capture any child elements with no attributes and no children. -->
            <xsl:for-each select="*[not(@*) and not(*)]">
                <xsl:attribute name="{name()}">
                    <xsl:value-of select="."/>
                </xsl:attribute>
            </xsl:for-each>
            <!-- Apply templates to **only** those children that have either
                attributes or children of their own, and to text. -->
            <xsl:apply-templates select="*[@* or *]|text()"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

关键区别:任何满足您条件的元素——没有子元素,没有属性,只有文本——不是通过应用模板得到处理,而是得到处理在那个 for-each 循环中.所以我们永远不会得到那个元素的副本.

The key difference: any element that meets your criteria -- has no child elements, has no attributes, only has text -- does not get processed by applying a template, and instead it gets processed within that for-each loop. So we never wind up with a copy of that element.

我们现在有一个明确的规定,即缺少文本的空元素将作为独立元素保留.所以对于像下面这样的代码片段,带有空的 EXTRA 元素:

We now have a clarified provision that empty elements that lack even text are to be kept as independent elements. So for a snippet like the following, with the empty EXTRA element:

<worker>
    <name>
        <doo atr="ss1">val4</doo>
        <make3>val4</make3>
        <EXTRA></EXTRA>
    </name>
</worker>

...我们希望输出如下:

... we would want output like:

<worker>
    <name make3="val4">
        <doo atr="ss1">val4</doo>
        <EXTRA/>
    </name>
</worker>

... 将 EXTRA 保持为一个独立的元素,并且只对 make3 元素进行属性化.

... which maintains EXTRA as an independent element, and only attribute-ifies the make3 element.

这个 XSL 应该可以解决问题.这将修改上面代码中的 select 语句.

This XSL should do the trick. This reworks the select statements from the code above.

<xsl:template match="*">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <!-- Capture any child elements with no attributes and no children,
            and that also have text. -->
        <xsl:for-each select="*[not(@*) and not(*) and text()]">
            <xsl:attribute name="{name()}">
                <xsl:value-of select="."/>
            </xsl:attribute>
        </xsl:for-each>
        <!-- Apply templates to **only** those children that have no text, or
            that have attributes or children of their own, and also apply to text. -->
        <xsl:apply-templates select="*[@* or * or not(text())] | text()"/>
    </xsl:copy>
</xsl:template>

这篇关于XSLT:没有属​​性且没有子元素的元素转换为父属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆