我们有一个包含许多类似isProduct,isActive,isMandatory标记节点的节点位置的文字可能是真或假的XML文档。

这是需要来操纵文档,并保持它们的结构,但是上述的节点转换为口头表示象下面这样:

< isProduct >True</ isProduct >   ===>   <Type>Product<Type>
< isProduct >False</ isProduct >  ===>   <Type/>

和相同的其他标志节点。

我们正在寻求一种可扩展和可伸缩的解决方案,可以与部署后最小的摩擦来配置。

通过扩展的;我们的意思是将有更多的案件;像2个标志位表示的状态;即isEmployee和isCustomer在文档中用于表示4个不同的命名东西.;因此4个可能的组合应该仅转化为像“雇员”,“客户”,“客户雇员”或“无”一个字符串。

通过在可伸缩;我们的意思是它可以被用于处理任何XML文档而无需其模式的现有的理解和对文档尺寸没有限制。

我们也明白,这可能使用XSLT来完成,我们可以写一个XSLT是一个接受任何文件,并增加了额外的节点产生相同的文档或更新?

有帮助吗?

解决方案

假设像这样的输入:

<gizmo>
  <isProduct>True</isProduct>
  <isFoo>False</isFoo>
  <isBar>True</isBar>
</gizmo>

通用的做法是:

<xsl:template match="gizmo">
  <xsl:copy>
    <xsl:apply-templates select="*" />
  </xsl:copy>
</xsl:template>

<xsl:template match="*[substring(local-name(), 1, 2) = 'is']">
  <Type>
    <xsl:if test=". = 'True'">
      <xsl:value-of select="substring-after(local-name(), 'is')" />
    </xsl:if>
  </Type>
</xsl:template>

哪些生产:

<gizmo>
  <Type>Product</Type>
  <Type />
  <Type>Bar</Type>
</gizmo>

一个更一般化的方法使用(重)改性恒等变换:

<!-- the identity template... well, sort of -->
<xsl:template match="node() | @*">
  <xsl:copy>
    <!-- all element-type children that begin with 'is' -->
    <xsl:variable name="typeNodes"  select="
      *[substring(local-name(), 1, 2) = 'is']
    " />

    <!-- all other children (incl. elements that don't begin with 'this ' -->
    <xsl:variable name="otherNodes" select="
      @* | node()[not(self::*) or self::*[substring(local-name(), 1, 2) != 'is']]
    " />

    <!-- identity transform all the "other" nodes -->
    <xsl:apply-templates select="$otherNodes" />

    <!-- collapse all the "type" nodes into a string -->
    <xsl:if test="$typeNodes">
      <Type>
        <xsl:variable name="typeString">
          <xsl:apply-templates select="$typeNodes" />
        </xsl:variable>
        <xsl:value-of select="substring-after($typeString, '-')" />
      </Type>
    </xsl:if>
  </xsl:copy>
</xsl:template>

<!-- this collapses all the "type" nodes into a string -->
<xsl:template match="*[substring(local-name(), 1, 2) = 'is']">
  <xsl:if test=". = 'True'">
    <xsl:text>-</xsl:text>
    <xsl:value-of select="substring-after(local-name(), 'is')" />
  </xsl:if>
</xsl:template>

<!-- prevent the output of empty text nodes -->
<xsl:template match="text()">
  <xsl:if test="normalize-space() != ''">
    <xsl:value-of select="." />
  </xsl:if>
</xsl:template>

上面的需要任何XML输入任何,并且输出相同的结构,仅命名<is*>元件被折叠成如短划线分隔的字符串单个<Type>节点:

<!-- in -->
<foo>
  <fancyNode />
  <gizmo>
    <isProduct>True</isProduct>
    <isFoo>False</isFoo>
    <isBar>True</isBar>
  </gizmo>
</foo>

<!-- out -->
<foo>
  <fancyNode />
  <gizmo>
    <Type>Product-Bar</Type>
  </gizmo>
</foo>

其他提示

下面是基于该身份转换在XSLT的溶液

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="node() | @*">
    <xsl:copy>
        <xsl:apply-templates select="node() | @*"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="isProduct">
    <xsl:choose>
      <xsl:when test=". = 'True'"><Type>Product</Type></xsl:when>
      <xsl:otherwise><Type/></xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top