为每个查询的元素添加属性集

Posted

技术标签:

【中文标题】为每个查询的元素添加属性集【英文标题】:Add attribute-set per queried element 【发布时间】:2021-08-14 12:39:11 【问题描述】:

我正在使用一个平面 JSON 源文件,从分层树的角度来看。作为 XSLT 转换的一部分,我希望定义组以指示哪个元素应具有某些属性集。输出的元素顺序并不重要。

这是我的代码的最小化版本,所以我想在 XSL 的顶部收集所有设置/配置/定义是有原因的。如果代码非常小,我认为直接在每个模板中添加请求的元素是有意义的。

我知道“if”元素行已被注释掉,并且可能需要(并扩展)正确的语法才能使解决方案发挥作用。

如果有另一种更好、更简单的方法来定义组也可以。

JSON:

<data>

  "flat": 
    "Milk": 12,
    "Duck": 32,
    "Beer": 8,
    "Cow": 43
  

</data>

XSL:

<?xml version="1.0" encoding="UTF-8"?>

<xsl:transform version="3.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:item="http://www.example.com/1"
  xmlns:inventory="http://www.example.com/2"
  expand-text="yes"
>

  <xsl:output method="xml" indent="yes"/>
  <xsl:mode on-no-match="shallow-skip"/>

  <!-- Categorization -->

<xsl:variable name="group-animals">Cow, Duck</xsl:variable>
<xsl:variable name="group-beverage">Milk, Beer</xsl:variable>

<!-- Variations of attribute settings -->

<xsl:attribute-set name="set-attributes-for-category-animals">
  <xsl:attribute name="contextRef">animals</xsl:attribute>
</xsl:attribute-set>

<xsl:attribute-set name="set-attributes-for-category-beverage">
    <xsl:attribute name="contextRef">beverage</xsl:attribute>
  </xsl:attribute-set>

  <!-- Parse JSON to XML -->

  <xsl:template match="data">
    <inventory>
      <xsl:apply-templates select="json-to-xml(.)/*"/>
    </inventory>
  </xsl:template>

<!-- Template -->

<!-- Planned logic:  -->

<!--
  If element defined in "group-animals" exist in JSON / XML map",
  then use "set-attributes-for-category-animals"
  If element defined in "group-beverage" exist in JSON / XML map",
  then use "set-attributes-for-category-beverage"
-->

  <xsl:template match="*[@key ='flat']">

    <xsl:for-each select="*">

      <!-- <xsl:if test=""> -->

      <xsl:element
        name="item:@key"
        use-attribute-sets="set-attributes-for-category-animals"
      >
        <xsl:value-of select="text()"/>
      </xsl:element>

    <!-- </xsl:if> -->

    </xsl:for-each>

  </xsl:template>

  </xsl:transform>

结果:

<?xml version="1.0" encoding="UTF-8"?>
<inventory xmlns:inventory="http://www.example.com/3"
           xmlns:item="http://www.example.com/1">
   <item:Milk contextRef="animals">12</item:Milk>
   <item:Duck contextRef="animals">32</item:Duck>
   <item:Beer contextRef="animals">8</item:Beer>
   <item:Cow contextRef="animals">43</item:Cow>
</inventory>

想要的结果:

<?xml version="1.0" encoding="UTF-8"?>
<inventory xmlns:inventory="http://www.example.com/3"
           xmlns:item="http://www.example.com/1">
   <item:Milk contextRef="beverage">12</item:Milk>
   <item:Duck contextRef="animals">32</item:Duck>
   <item:Beer contextRef="beverage">8</item:Beer>
   <item:Cow contextRef="animals">43</item:Cow>
</inventory>

【问题讨论】:

【参考方案1】:

我会将逗号分隔的值标记为字符串序列,然后比较键,例如

<?xml version="1.0" encoding="UTF-8"?>

<xsl:transform version="3.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:item="http://www.example.com/1"
  xmlns:inventory="http://www.example.com/2"
  expand-text="yes"
>

  <xsl:output method="xml" indent="yes"/>
  <xsl:mode on-no-match="shallow-skip"/>

  <!-- Categorization -->

<xsl:param name="group-animals">Cow, Duck</xsl:param>

<xsl:param name="animals" select="tokenize($group-animals, ',\s*')"/>

<xsl:param name="group-beverage">Milk, Beer</xsl:param>

<xsl:param name="beverages" select="tokenize($group-beverage, ',\s*')"/>

<!-- Variations of attribute settings -->

<xsl:attribute-set name="set-attributes-for-category-animals">
  <xsl:attribute name="contextRef">animals</xsl:attribute>
</xsl:attribute-set>

<xsl:attribute-set name="set-attributes-for-category-beverage">
    <xsl:attribute name="contextRef">beverage</xsl:attribute>
  </xsl:attribute-set>

  <!-- Parse JSON to XML -->

  <xsl:template match="data">
    <inventory>
      <xsl:apply-templates select="json-to-xml(.)/*"/>
    </inventory>
  </xsl:template>

<!-- Template -->

<!-- Planned logic:  -->

<!--
  If element defined in "group-animals" exist in JSON / XML map",
  then use "set-attributes-for-category-animals"
  If element defined in "group-beverage" exist in JSON / XML map",
  then use "set-attributes-for-category-beverage"
-->

  <xsl:template match="*[@key ='flat']/*[@key = $animals]">
     <xsl:element
        name="item:@key"
        use-attribute-sets="set-attributes-for-category-animals">
       <xsl:value-of select="."/>
     </xsl:element>
  </xsl:template>
  
  <xsl:template match="*[@key ='flat']/*[@key = $beverages]">
     <xsl:element
        name="item:@key"
        use-attribute-sets="set-attributes-for-category-beverage">
       <xsl:value-of select="."/>
     </xsl:element>
  </xsl:template>


  </xsl:transform>

与例如的一般价值比较= 是一种存在比较,因此如果key 属性的属性值等于字符串序列$animals 中的至少一个字符串值,则@key = $animals 为真。

整个匹配匹配具有key 属性值flat 的父元素的子元素,其中子元素的key 值在$animals 的序列中。

【讨论】:

该建议效果很好。一个问题。匹配线有什么作用? “*[@key ='flat']/*[@key = $animals]”。它是否将“平面”的孩子与参数动物进行比较。如果匹配,它会设置 aminals 的属性? 与 e.g. 的一般值比较= 是一种存在比较,因此如果key 属性的属性值等于字符串序列$animals 中的至少一个字符串值,则@key = $animals 为真。整个匹配匹配具有key 属性值flat 的父元素的子元素,其中子元素的key 值在$animals 的序列中。 能否请您将您的最新评论移至给定答案中,我将继续接受答案。 @Toolbox,我已将= 比较和匹配模式的解释添加到答案中。

以上是关于为每个查询的元素添加属性集的主要内容,如果未能解决你的问题,请参考以下文章

如何使用没有临时表的 SQL 查询为组中的每个元素添加序列号

Python Django:在视图中向对象添加属性还是制作数据字典更好?

在一次操作中更改元素属性(数据集) - 避免回流

SQL为每个属性添加总和行

[ jquery 方法 addClass(class|fn) ] 此方法为每个匹配的元素添加指定的类名

XSLT Grouping's:将父级添加到子元素中的元素集