【问题标题】:Identity Template specific elements, exclude everything else身份模板特定元素,排除其他所有元素
【发布时间】:2016-03-28 15:35:57
【问题描述】:

如何使用以下 XML 仅将地址详细信息提取为 CSV 格式?

我相信我需要一个基于身份模板的样式表,尽管我找到的示例很简单,并且在列表中列出了您要排除的元素。是否有一种简单的方法可以排除除 Address 和 AddressLine 之外的所有内容?

我正在使用 .NET 来处理 XLST 转换。到目前为止我提出的样式表没有返回任何内容。

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

  <xsl:param name="delim" select="','" />
  <xsl:param name="quote" select="'&quot;'" />
  <xsl:param name="break" select="'&#xa;'" />

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

  <xsl:template match="AddressLine" priority="9">
    <xsl:value-of select="concat($quote, ., $quote, $delim)"/>
  </xsl:template>

  <xsl:template match="*" priority="0" />
</xsl:stylesheet>
<Sample Version="6" Date="2012-05-11">
  <Header>
    <CreatedDate>2015-12-02</CreatedDate>
    <CreatedTime>10:31:42</CreatedTime>
  </Header>
  <Message Group="1" Type="1" Protocol="1">
    <MessageHeader>
      <MessageReferenceNumber>1</MessageReferenceNumber>
    </MessageHeader>
    <TransactionHeader>
      <ReportPeriodStartDate>2002-04-01</ReportPeriodStartDate>
      <ReportPeriodEndDate>2015-11-30</ReportPeriodEndDate>
    </TransactionHeader>
    <Episode>
      <Person>
        <General>
          <Verified Status="02">
            <Identifier>001</Identifier>
            <PersonName>
              <Name>
                <FirstName>Foo</FirstName>
                <Surname>Bar</Surname>
              </Name>
            </PersonName>
            <Address>
              <AddressLine></AddressLine>
              <AddressLine>Street</AddressLine>
              <AddressLine>Town</AddressLine>
              <AddressLine>City</AddressLine>
            </Address>
          </Verified>
        </General>
      </Person>
      <Session>
        <Input>
          <StartDate>2015-10-31</StartDate>
          <StartTime>17:15:00</StartTime>
        </Input>
        <Output>
          <StatusCode>8</StatusCode>
          <LocationCode>9</LocationCode>
        </Output>
      </Session>
    </Episode>
    <MessageTrailer>
      <MessageReferenceNumber>1</MessageReferenceNumber>
    </MessageTrailer>
  </Message>
  <Message Group="1" Type="1" Protocol="1">
    <MessageHeader>
      <MessageReferenceNumber>2</MessageReferenceNumber>
    </MessageHeader>
    <TransactionHeader>
      <ReportPeriodStartDate>2002-04-01</ReportPeriodStartDate>
      <ReportPeriodEndDate>2015-11-30</ReportPeriodEndDate>
    </TransactionHeader>
    <Episode>
      <Person>
        <General>
          <Verified Status="02">
            <Identifier>002</Identifier>
            <PersonName>
              <Name>
                <FirstName>Foo</FirstName>
                <Surname>Bar</Surname>
              </Name>
            </PersonName>
            <Address>
              <AddressLine></AddressLine>
              <AddressLine>Street</AddressLine>
              <AddressLine>Town</AddressLine>
              <AddressLine>City</AddressLine>
            </Address>
          </Verified>
        </General>
      </Person>
      <Session>
        <Input>
          <StartDate>2015-10-31</StartDate>
          <StartTime>17:15:00</StartTime>
        </Input>
        <Output>
          <StatusCode>8</StatusCode>
          <LocationCode>9</LocationCode>
        </Output>
      </Session>
    </Episode>
    <MessageTrailer>
      <MessageReferenceNumber>2</MessageReferenceNumber>
    </MessageTrailer>
  </Message>
  <Trailer>
    <RecordCount>2</RecordCount>
  </Trailer>
</Sample>

【问题讨论】:

  • 请注意,您当前的 XSLT 不返回任何内容的原因是模板匹配 &lt;xsl:template match="*" priority="0" /&gt;。这实际上比身份模板具有更高的优先级(默认优先级为 -0.5)。因此,此模板匹配根元素Sample,并在此处停止处理。 (如果您希望它跳过该元素并继续处理其子元素,则应显式添加 &lt;xsl:apply-templates /&gt; 指令)。

标签: .net xml xslt xslt-1.0


【解决方案1】:

如果你想创建纯文本,我认为身份转换模板没有意义,你只需要一个根节点的模板

<xsl:template match="/">
  <xsl:apply-templates select="//Address"/>
</xsl:template>

然后您可以编写模板来执行您想要或需要为Address 或其子AddressLine 输出的内容,就像您似乎拥有的那样。

作为替代方案,您可以利用现有的默认模板递归处理子节点,只需确保覆盖 text() 节点的模板,否则将输出所有元素的所有文本。

所以要么试试

<xsl:template match="/">
  <xsl:apply-templates select="//Address"/>
</xsl:template>

  <xsl:template match="AddressLine">
    <xsl:value-of select="concat($quote, ., $quote, $delim)"/>
  </xsl:template>

或者仅仅是一种方法

<xsl:template match="*[not(self::Address)]/text()"/>

<xsl:template match="AddressLine">
  <xsl:value-of select="concat($quote, ., $quote, $delim)"/>
</xsl:template>

在这两种情况下,我都不确定您想要的确切结果是生成的行,因此可能需要进行一些调整以插入或添加换行符。

【讨论】:

    【解决方案2】:

    一种简单的方法是“重新定义”内置模板规则并仅复制选定的规则 - 在本例中为 Address 和子节点:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:template match="*|@*">
        <xsl:apply-templates select="*" />
      </xsl:template>
      <xsl:template match="Address">
        <xsl:copy-of select="." />
      </xsl:template>
    </xsl:stylesheet>
    

    导致

    <?xml version="1.0"?>
    <Address>
        <AddressLine/>
        <AddressLine>Street</AddressLine>
        <AddressLine>Town</AddressLine>
        <AddressLine>City</AddressLine>
    </Address>
    <Address>
        <AddressLine/>
        <AddressLine>Street</AddressLine>
        <AddressLine>Town</AddressLine>
        <AddressLine>City</AddressLine>
    </Address>
    

    【讨论】:

      【解决方案3】:

      无需添加显式模板优先级,只需使用与AddressLine 匹配的模板和另一个模板,以防止默认输出所有文本节点。

      样式表

      <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      
        <xsl:output method="text" encoding="utf-8" />
        <xsl:strip-space elements="*"/>
      
        <xsl:param name="delim" select="','" />
        <xsl:param name="quote" select="'&quot;'" />
        <xsl:param name="break" select="'&#xa;'" />
      
      
        <xsl:template match="AddressLine">
          <xsl:value-of select="concat($quote, ., $quote, $delim)"/>
        </xsl:template>
      
        <xsl:template match="text()"/>
      
      </xsl:stylesheet>
      

      文本输出

      "","Street","Town","City","","Street","Town","City",
      

      如果您预计输出会有所不同,请说明应该更改的内容。

      【讨论】:

        猜你喜欢
        • 2023-03-19
        • 1970-01-01
        • 2020-12-11
        • 1970-01-01
        • 2021-11-24
        • 2022-01-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多