XSLT - 根据另一个元素子值删除元素

问题描述 投票:0回答:2

我正在尝试根据另一个元素子值删除元素。 这是示例 xml 文件:

<Information>
    <List>
        <Element ID="101278">
            <MetaData>
                <Value AttributeID="DisplayOrNo">no</Value>
              </MetaData>
        </Element>
        <Element ID="101277">
            <MetaData>
                <Value AttributeID="DisplayOrNo">yes</Value>
              </MetaData>
        </Element>
    </List>
<Products>
    <Product ID="3333">
      <Name>test_name</Name>
      <Values>
        <Value ElementID="101278">test_text</Value>
        <Value ElementID="101277">test_text</Value>
      </Values>
    </Product>
  </Products>
</Information>

如果元素列表/元素/元数据/值的值为否,我想删除产品/值中的元素值。 值元素将具有有关元素的 ID 属性的信息。这可能有助于匹配它们。

我期待这样的事情:

<Information>
    <List>
        <Element ID="101278">
            <MetaData>
                <Value AttributeID="DisplayOrNo">no</Value>
              </MetaData>
        </Element>
        <Element ID="101277">
            <MetaData>
                <Value AttributeID="DisplayOrNo">yes</Value>
              </MetaData>
        </Element>
    </List>
<Products>
    <Product ID="3333">
      <Name>test_name</Name>
      <Values>
        <Value ElementID="101277">test_text</Value>
      </Values>
    </Product>
  </Products>
</Information>

您认为在匹配和删除 Value 元素之后,还可以完全删除 Information 中的整个 List 吗?或者我是否必须制作第二个 XSLT 才能删除 List ? 应该看起来像这里:

<Information>
<Products>
    <Product ID="3333">
      <Name>test_name</Name>
      <Values>
        <Value ElementID="101277">test_text</Value>
      </Values>
    </Product>
  </Products>
</Information>
xml xslt xslt-2.0
2个回答
0
投票

当前支持的大多数 XSLT 处理器版本都支持 XSLT 3.0(当前版本)或 XSLT 1.0。所以假设你使用例如当前支持 XSLT 2 的 Saxon 版本,它还将支持 XSLT 3 累加器:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:mode on-no-match="shallow-copy" use-accumulators="display" streamable="yes"/>

  <xsl:accumulator name="display" as="xs:string*" initial-value="()" streamable="yes">
    <xsl:accumulator-rule match="List/Element[@ID]/MetaData/Value[@AttributeID = 'DisplayOrNo']/text()[. = 'yes']" select="$value, string(ancestor::Element/@ID)"/>
  </xsl:accumulator>
  
  <xsl:template match="List"/>
  
  <xsl:template match="Products/Product/Values/Value[not(@ElementID = accumulator-before('display'))]"/>
  
</xsl:stylesheet>

0
投票

以下是如何在 XSLT 2.0(甚至 XSLT 1.0)中执行此操作:

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

<xsl:key name="elem-by-id" match="Element[MetaData/Value[@AttributeID='DisplayOrNo']='yes']" use="@ID" />

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

<xsl:template match="List"/>

<xsl:template match="Value[not(key('elem-by-id', @ElementID))]"/>
  
</xsl:stylesheet>
© www.soinside.com 2019 - 2024. All rights reserved.