使用XSLT删除CDATA值为空的元素。

huangapple go评论66阅读模式
英文:

Remove element with XSLT where CDATA value is empty

问题

我对XSLT相当陌生,发现很难正确理解它...

我想要实现的是,将XML中每个CDATA没有值的<text>元素删除。

我的XML如下:

<description>
  <internet>
    <texts_short>
      <text locale="de"><![CDATA[]]></text>
      <text locale="en"><![CDATA[EXF/RETAIL]]></text>
    </texts_short>
    <texts_long>
      <text locale="de"><![CDATA[]]></text>
    </texts_long>
  </internet>
  <vehicle>
    <texts_short/>
    <texts_long>
      <text locale="en"><![CDATA[Backend Functions Bundle]]></text>
    </texts_long>
    <texts_text2speech>
      <text locale="de"><![CDATA[]]></text>
    </texts_text2speech>
  </vehicle>
</description>

我已经准备好了以下的XSLT,它会删除没有条件的每个text元素:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  
  <xsl:output method="xml" indent="yes"/>
  <xsl:strip-space elements="*"/>
  
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="text"/>
  
</xsl:stylesheet>

要实现只删除CDATA值为空的<text>元素,可以修改XSLT如下:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  
  <xsl:output method="xml" indent="yes"/>
  <xsl:strip-space elements="*"/>
  
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="text">
    <xsl:if test="string-length(normalize-space(.//text())) > 0">
      <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
    </xsl:if>
  </xsl:template>
  
</xsl:stylesheet>

这个XSLT将只保留具有非空CDATA值的<text>元素,其他的将被删除。

英文:

I am quite new to XSLT and find it very hard to understand properly..

I want to achieve that every <text> element where my CDATA has no value should be removed from the XML.

My XML looks like this:

&lt;description&gt;
  &lt;internet&gt;
    &lt;texts_short&gt;
      &lt;text locale=&quot;de&quot;&gt;&lt;![CDATA[]]&gt;&lt;/text&gt;
      &lt;text locale=&quot;en&quot;&gt;&lt;![CDATA[EXF/RETAIL]]&gt;&lt;/text&gt;
    &lt;texts_long&gt;
      &lt;text locale=&quot;de&quot;&gt;&lt;![CDATA[]]&gt;&lt;/text&gt;
    &lt;/texts_long&gt;
  &lt;/internet&gt;
  &lt;vehicle&gt;
    &lt;texts_short/&gt;
    &lt;texts_long&gt;
      &lt;text locale=&quot;en&quot;&gt;&lt;![CDATA[Backend Functions Bundle]]&gt;&lt;/text&gt;
    &lt;/texts_long&gt;
    &lt;texts_text2speech&gt;
      &lt;text locale=&quot;de&quot;&gt;&lt;![CDATA[]]&gt;&lt;/text&gt;
    &lt;/texts_text2speech&gt;
  &lt;/vehicle&gt;
&lt;/description&gt;

I have already prepared the following XSLT which removes every text element with no condition:

&lt;xsl:stylesheet version=&quot;1.0&quot; xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&gt;

&lt;xsl:output method=&quot;xml&quot; indent=&quot;yes&quot;/&gt;
&lt;xsl:strip-space elements=&quot;*&quot;/&gt;

&lt;xsl:template match=&quot;@*|node()&quot;&gt;
	&lt;xsl:copy&gt;
		&lt;xsl:apply-templates select=&quot;@*|node()&quot;/&gt;
	&lt;/xsl:copy&gt;
&lt;/xsl:template&gt;

&lt;xsl:template match=&quot;text&quot;/&gt;

&lt;/xsl:stylesheet&gt;

How can I achieve that only the <text> elements with empty CDATA value will be removed - so that only the one with text "EXF/RETAIL" and "Backend Functions Bundle" will stay?

Thank you in advance!

答案1

得分: 1

你可以使用&lt;xsl:template match=&quot;text[not(normalize-space())]&quot;/&gt;,但这将移除没有内容、空的CDATA部分、只包含空格的CDATA部分等的text元素。在XSLT中无法知道元素的内容是由CDATA部分还是普通文本节点在词法标记中提供的。

英文:

What you can do is use &lt;xsl:template match=&quot;text[not(normalize-space())]&quot;/&gt; but that will remove text elements having no content, an empty CDATA section, a CDATA section with only white space etc. There is no way in XSLT to know whether the element's content was provided in the lexical markup by a CDATA section or an ordinary text node.

答案2

得分: 0

翻译后的代码部分如下:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" cdata-section-elements="text"/>
    <xsl:strip-space elements="*"/>

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

    <xsl:template match="text[not(normalize-space())]"/>
</xsl:stylesheet>
英文:

It looks like adding cdata-section-elements="text" to the output together with Martin Honnen's answer solved my problem:

&lt;xsl:stylesheet version=&quot;1.0&quot; xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;&gt;

&lt;xsl:output method=&quot;xml&quot; indent=&quot;yes&quot; cdata-section-elements=&quot;text&quot;/&gt;
&lt;xsl:strip-space elements=&quot;*&quot;/&gt;

&lt;xsl:template match=&quot;@*|node()&quot;&gt;
	&lt;xsl:copy&gt;
		&lt;xsl:apply-templates select=&quot;@*|node()&quot;/&gt;
	&lt;/xsl:copy&gt;
&lt;/xsl:template&gt;

&lt;xsl:template match=&quot;text[not(normalize-space())]&quot;/&gt;
&lt;/xsl:stylesheet&gt;

huangapple
  • 本文由 发表于 2023年2月6日 17:39:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/75359578.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定