【问题标题】:Filter out certain XML nodes and form another XML with these nodes and their ancestors and child nodes过滤掉某些 XML 节点,并与这些节点及其祖先和子节点形成另一个 XML
【发布时间】:2021-03-17 18:19:03
【问题描述】:

我有以下 XML 数据,我需要过滤某些 XML 节点并使用这些节点形成另一个 XML 数据,它是祖先节点以及它的所有子节点。我是 XSLT 的新手,并尝试了使用 XSLT 的不同方法,但没有任何效果。

这是否可以在 XSLT 中实现?

数据:

<?xml version="1.0" encoding="UTF-8"?>
<MessageDetails>`enter code here`
   <challengeDetails>
      <challengeId>1000000017</challengeId>
      <challengeCode>WEEKACTIVE</challengeCode>
      <challengeCategory>StayActive</challengeCategory>
      <challengePeriodsDetails>
         <periodId>1000000064</periodId>
         <periodNumber>2</periodNumber>
         <periodStatus>INPROGRESS</periodStatus>
         <challengeAwardIssued>
            <awardType>GAME</awardType>
            <awardCode>GCH009</awardCode>
         </challengeAwardIssued>
         <challengeAwardIssued>
            <awardType>REWARD</awardType>
            <awardCode>EHNC001</awardCode>
         </challengeAwardIssued>
      </challengePeriodsDetails>
      <challengePeriodsDetails>
         <periodId>1000000065</periodId>
         <periodNumber>3</periodNumber>
         <periodStatus>COMPLETED</periodStatus>
         <challengeAwardIssued>
            <awardType>REWARD</awardType>
            <awardCode>EHNC002</awardCode>
         </challengeAwardIssued>
      </challengePeriodsDetails>
   </challengeDetails>
   <challengeDetails>
      <challengeId>1000000018</challengeId>
      <challengeCode>QUITSUGAR</challengeCode>
      <challengeCategory>QuitSugar</challengeCategory>
      <challengePeriodsDetails>
         <periodId>1000000066</periodId>
         <periodNumber>2</periodNumber>
         <periodStatus>INPROGRESS</periodStatus>
         <challengeAwardIssued>
            <awardType>REWARD</awardType>
            <awardCode>EHNC001</awardCode>
         </challengeAwardIssued>
      </challengePeriodsDetails>
      <challengePeriodsDetails>
         <periodId>1000000067</periodId>
         <periodNumber>3</periodNumber>
         <periodStatus>COMPLETED</periodStatus>
         <challengeAwardIssued>
            <awardType>GAME</awardType>
            <awardCode>EHNC001</awardCode>
         </challengeAwardIssued>
      </challengePeriodsDetails>
   </challengeDetails>
</MessageDetails>

搜索条件 #1:awardType = GAME

<?xml version="1.0" encoding="UTF-8"?>
<MessageDetails>
   <challengeDetails>
      <challengeId>1000000017</challengeId>
      <challengeCode>WEEKACTIVE</challengeCode>
      <challengeCategory>StayActive</challengeCategory>
      <challengePeriodsDetails>
         <periodId>1000000064</periodId>
         <periodNumber>2</periodNumber>
         <periodStatus>INPROGRESS</periodStatus>
         <challengeAwardIssued>
            <awardType>GAME</awardType>
            <awardCode>GCH009</awardCode>
         </challengeAwardIssued>
      </challengePeriodsDetails>
   </challengeDetails>
   <challengeDetails>
      <challengeId>1000000018</challengeId>
      <challengeCode>QUITSUGAR</challengeCode>
      <challengeCategory>QuitSugar</challengeCategory>
      <challengePeriodsDetails>
         <periodId>1000000067</periodId>
         <periodNumber>3</periodNumber>
         <periodStatus>COMPLETED</periodStatus>
         <challengeAwardIssued>
            <awardType>GAME</awardType>
            <awardCode>GCH008</awardCode>
         </challengeAwardIssued>
      </challengePeriodsDetails>
   </challengeDetails>
</MessageDetails>

搜索条件 #2:awardType = GAME 和 periodStatus = COMPLETED 和 challengeCode = QUITSUGAR

<?xml version="1.0" encoding="UTF-8"?>
<MessageDetails>
   <challengeDetails>
      <challengeId>1000000018</challengeId>
      <challengeCode>QUITSUGAR</challengeCode>
      <challengeCategory>QuitSugar</challengeCategory>
      <challengePeriodsDetails>
         <periodId>1000000067</periodId>
         <periodNumber>3</periodNumber>
         <periodStatus>COMPLETED</periodStatus>
         <challengeAwardIssued>
            <awardType>GAME</awardType>
            <awardCode>GCH008</awardCode>
         </challengeAwardIssued>
      </challengePeriodsDetails>
   </challengeDetails>
</MessageDetails>

搜索条件 #3:challengeCode = WEEKACTIVE & periodId = 1000000064

    <?xml version="1.0" encoding="UTF-8"?>
    <MessageDetails>
       <challengeDetails>
          <challengeId>1000000017</challengeId>
          <challengeCode>WEEKACTIVE</challengeCode>
          <challengeCategory>StayActive</challengeCategory>
          <challengePeriodsDetails>
             <periodId>1000000064</periodId>
             <periodNumber>2</periodNumber>
             <periodStatus>INPROGRESS</periodStatus>
             <challengeAwardIssued>
                <awardType>GAME</awardType>
                <awardCode>GCH009</awardCode>
             </challengeAwardIssued>
          </challengePeriodsDetails>
       </challengeDetails>
    </MessageDetails>

搜索条件 #4:periodId = 1000000066

<?xml version="1.0" encoding="UTF-8"?>
<MessageDetails>
   <challengeDetails>
      <challengeId>1000000018</challengeId>
      <challengeCode>QUITSUGAR</challengeCode>
      <challengeCategory>QuitSugar</challengeCategory>
      <challengePeriodsDetails>
         <periodId>1000000066</periodId>
         <periodNumber>2</periodNumber>
         <periodStatus>INPROGRESS</periodStatus>
         <challengeAwardIssued>
            <awardType>REWARD</awardType>
            <awardCode>EHNC001</awardCode>
         </challengeAwardIssued>
      </challengePeriodsDetails>
   </challengeDetails>
</MessageDetails>

搜索条件 #5:awardType = 'GAME' 和 AwardCode='EHNC001'

需要的输出:

<?xml version="1.0" encoding="UTF-8"?>
<MessageDetails>`enter code here`
       <challengeDetails>
          <challengeId>1000000018</challengeId>
          <challengeCode>QUITSUGAR</challengeCode>
          <challengeCategory>QuitSugar</challengeCategory>
          <challengePeriodsDetails>
             <periodId>1000000067</periodId>
             <periodNumber>3</periodNumber>
             <periodStatus>COMPLETED</periodStatus>
             <challengeAwardIssued>
                <awardType>GAME</awardType>
                <awardCode>EHNC001</awardCode>
             </challengeAwardIssued>
          </challengePeriodsDetails>
       </challengeDetails>
    </MessageDetails>

收到的输出:

<?xml version="1.0" encoding="UTF-8"?>
<MessageDetails>`enter code here`
       <challengeDetails>
          <challengeId>1000000017</challengeId>
          <challengeCode>WEEKACTIVE</challengeCode>
          <challengeCategory>StayActive</challengeCategory>
          <challengePeriodsDetails>
             <periodId>1000000064</periodId>
             <periodNumber>2</periodNumber>
             <periodStatus>INPROGRESS</periodStatus>
          </challengePeriodsDetails>
       </challengeDetails>
       <challengeDetails>
          <challengeId>1000000018</challengeId>
          <challengeCode>QUITSUGAR</challengeCode>
          <challengeCategory>QuitSugar</challengeCategory>
          <challengePeriodsDetails>
             <periodId>1000000067</periodId>
             <periodNumber>3</periodNumber>
             <periodStatus>COMPLETED</periodStatus>
             <challengeAwardIssued>
                <awardType>GAME</awardType>
                <awardCode>EHNC001</awardCode>
             </challengeAwardIssued>
          </challengePeriodsDetails>
       </challengeDetails>
    </MessageDetails>

使用的 XSLT:

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

<xsl:template match="/MessageDetails/challengeDetails[not(challengePeriodsDetails/challengeAwardIssued/awardType = 'GAME' and challengePeriodsDetails/challengeAwardIssued/awardCode= 'EHNC001')]" />

<xsl:template match="/MessageDetails/challengeDetails/challengePeriodsDetails[not(challengeAwardIssued/awardType = 'GAME' and challengeAwardIssued/awardCode= 'EHNC001')]" />

<xsl:template match="/MessageDetails/challengeDetails/challengePeriodsDetails/challengeAwardIssued[not(awardType = 'GAME' and awardCode= 'EHNC001')]" />

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

</xsl:stylesheet>

【问题讨论】:

  • 我会在您的程序代码中使用 XML 和 XPath。读取每个标准 XML,并在原始 XML 中标记匹配的元素。然后删除所有不匹配的元素,并将 XML 保存为副本。
  • 感谢@WilliamWalseth 的回复。让我也检查一下。

标签: xml xslt xsd xml-parsing xslt-3.0


【解决方案1】:

据我了解,您想过滤掉 challengeDetailschallengePeriodsDetails 给定一些谓词。要过滤掉 XSL 中的元素,您只需提供与您不想要的元素匹配的空模板。

查询 1

这是一个不错且简单的开始查询。只需从 copy-all 模板node()|@* 开始,添加两条规则即可过滤掉不需要的内容。

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

  <xsl:template match="/MessageDetails/challengeDetails[
      not(challengePeriodsDetails/challengeAwardIssued/awardType = 'GAME')
    ]" />

  <xsl:template match="/MessageDetails/challengeDetails/challengePeriodsDetails[
      not(challengeAwardIssued/awardType = 'GAME')
    ]" />

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

</xsl:stylesheet>

查询 2

这里的关键是过滤掉不满足两个谓词的challengePeriodsDetails。我们处理这些元素,not 处理challengeDetails,这就是谓词包含另一个谓词的原因。没有它,我们会过滤掉太多数据。

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

  <xsl:template match="/MessageDetails/challengeDetails[
      not(challengePeriodsDetails[
        challengeAwardIssued/awardType = 'GAME' and periodStatus = 'COMPLETED'
      ])
    ]" />

  <xsl:template match="/MessageDetails/challengeDetails/challengePeriodsDetails[
      not(challengeAwardIssued/awardType = 'GAME' and periodStatus = 'COMPLETED')
    ]" />

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

</xsl:stylesheet>

查询 3

这里的特殊性是我们不需要担心模板中关于challengePeriodsDetails的challengeCode,因为它的父级无论如何都不会出现在最终文档中。

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

  <xsl:template match="/MessageDetails/challengeDetails[
      not(challengeCode = 'WEEKACTIVE' and challengePeriodsDetails/periodId = '1000000064')
    ]" />

  <xsl:template match="/MessageDetails/challengeDetails/challengePeriodsDetails[
      not(periodId = '1000000064')
    ]" />

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

</xsl:stylesheet>

查询 4

这个看起来像查询1,我只能建议你在看代码之前自己尝试做,以证明自己有进步。

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

  <xsl:template match="/MessageDetails/challengeDetails[not(challengePeriodsDetails/periodId = '1000000066')]" />

  <xsl:template match="/MessageDetails/challengeDetails/challengePeriodsDetails[not(periodId = '1000000066')]" />

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

</xsl:stylesheet>

查询 5

你离得太近了!诀窍是针对相同的challengeAwardIssued 测试awardTypeawardCode。您必须在此节点上使用测试。这是一个解决方案:

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

  <xsl:template match="/MessageDetails/challengeDetails[
      not(challengePeriodsDetails/challengeAwardIssued[
        awardType = 'GAME' and awardCode = 'EHNC001'
      ])
    ]" />

  <xsl:template match="/MessageDetails/challengeDetails/challengePeriodsDetails[
      not(challengeAwardIssued[
        awardType = 'GAME' and awardCode = 'EHNC001'
      ])
    ]" />

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

</xsl:stylesheet>

【讨论】:

  • 感谢@Fabian。它的工作。请您帮忙弄清楚上面添加的场景#5。使用 XSLT,我使用的似乎是 challengeDetails 和 challengePeriodDetails 节点,awardType = 'GAME' 和 AwardCode= 'EHNC001' 从多个 challengAwardIssued 节点匹配,因此第一个 challengeDetails 和 challengePeriodDetails 块正在输出。
  • 几乎!我相应地更新了我的答案:-)
  • 不客气!请使用标记接受答案,以便网站的其他成员知道他们不应该再关注这个问题:-)
猜你喜欢
  • 1970-01-01
  • 2019-04-30
  • 1970-01-01
  • 2019-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-22
相关资源
最近更新 更多