2

我该如何处理这个,在 XML 文件中连接类似的 XML 标签

我有以下格式的 XML::

<addressbook>
 <address>
    <first-name>Chester Hasbrouck</first-name>
     <Descritpion>Hi</Descritpion>
     <Descritpion>This is Chester </Descritpion>
   <street>1234 Main Street</street>
  <city>Sheboygan</city>
  <state>WI</state>
  <zip>48392</zip>
 </address>
 <address>
    <first-name>Mary</first-name>
     <Descritpion>Hi</Descritpion>
     <Descritpion>This is Mary </Descritpion>
     <Descritpion>Bye</Descritpion>
     <street>283 First Avenue</street>
  <city>Skunk Haven</city>
  <state>MA</state>
  <zip>02718</zip>
 </address>
</addressbook>

我需要以下格式的人请为此建议 XSLT。

<addressbook>
 <address>
    <first-name>Chester Hasbrouck</first-name>
     <Descritpion>Hi | This is Chester </Descritpion>
   <street>1234 Main Street</street>
  <city>Sheboygan</city>
  <state>WI</state>
  <zip>48392</zip>
 </address>
 <address>
    <first-name>Mary</first-name>
     <Descritpion>Hi | This is Mary | Bye</Descritpion>
     <street>283 First Avenue</street>
  <city>Skunk Haven</city>
  <state>MA</state>
  <zip>02718</zip>
 </address>
</addressbook>
4

3 回答 3

1

这种转变

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

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

 <xsl:template match="Descritpion[not(preceding-sibling::*[1][self::Descritpion])]">
  <Descritpion>
   <xsl:value-of select="."/>
   <xsl:apply-templates select="following-sibling::Descritpion/text()"/>
  </Descritpion>
 </xsl:template>

 <xsl:template match="Descritpion/text()">
   <xsl:value-of select="concat(' | ', .)"/>
 </xsl:template>
 <xsl:template match="Descritpion"/>
</xsl:stylesheet>

应用于提供的 XML 文档时:

<addressbook>
    <address>
        <first-name>Chester Hasbrouck</first-name>
        <Descritpion>Hi</Descritpion>
        <Descritpion>This is Chester </Descritpion>
        <street>1234 Main Street</street>
        <city>Sheboygan</city>
        <state>WI</state>
        <zip>48392</zip>
    </address>
    <address>
        <first-name>Mary</first-name>
        <Descritpion>Hi</Descritpion>
        <Descritpion>This is Mary </Descritpion>
        <Descritpion>Bye</Descritpion>
        <street>283 First Avenue</street>
        <city>Skunk Haven</city>
        <state>MA</state>
        <zip>02718</zip>
    </address>
</addressbook>

产生想要的正确结果

<addressbook>
   <address>
      <first-name>Chester Hasbrouck</first-name>
      <Descritpion>Hi | This is Chester </Descritpion>
      <street>1234 Main Street</street>
      <city>Sheboygan</city>
      <state>WI</state>
      <zip>48392</zip>
   </address>
   <address>
      <first-name>Mary</first-name>
      <Descritpion>Hi | This is Mary  | Bye</Descritpion>
      <street>283 First Avenue</street>
      <city>Skunk Haven</city>
      <state>MA</state>
      <zip>02718</zip>
   </address>
</addressbook>

说明

  1. 身份规则“按原样”复制每个节点。

  2. Descritpion元素通常通过使用空体模板匹配覆盖标识模板而被忽略/删除Descritpion

  3. 只有Descritpion紧接其前面的兄弟元素不是 aDescritpion本身的元素才会被另一个覆盖模板特殊处理。这里复制元素的字符串值,然后将模板应用于以下兄弟元素的所有文本节点子Descritpion元素。

  4. 匹配Descritpion元素的 text-node-child 的模板实现了所需的文本连接。

于 2012-06-20T12:55:53.870 回答
0

为此,您可以在身份转换的基础上进行构建,但添加额外的规则来处理您感兴趣的元素

我认为您首先需要匹配其中没有子元素的元素

<xsl:template match="*[not(*)]" priority="1">

然后,您将向其中添加代码以输出当前文本值,然后选择所有具有相同名称的后续兄弟的文本值(将在它们之前使用分隔符输出)

<xsl:apply-templates 
   select="following-sibling::*[local-name() = local-name(current())]/text()" 
   mode="concat"/>

您还需要添加一个模板来忽略与前一个兄弟同名的元素,这样它们就不会得到两次输出

<xsl:template 
    match="*[not(*)][local-name() = local-name(preceding-sibling::*[1])]" 
    priority="2" />

请注意此处优先级属性的使用,因此 XSLT 处理器首先匹配具有较高优先级的处理器。

这是完整的 XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>

   <xsl:template match="*[not(*)]" priority="1">
      <xsl:copy>
         <xsl:value-of select="normalize-space(.)"/>
         <xsl:apply-templates select="following-sibling::*[local-name() = local-name(current())]/text()" mode="concat"/>
      </xsl:copy>
   </xsl:template>

   <xsl:template match="*[not(*)][local-name() = local-name(preceding-sibling::*[1])]" priority="2"/>

   <xsl:template match="text()" mode="concat">
      <xsl:value-of select="concat(' | ', normalize-space(.))"/>
   </xsl:template>

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

应用于您的示例 XML 时,将输出以下内容

<addressbook>
   <address>
      <first-name>Chester Hasbrouck</first-name>
      <Descritpion>Hi | This is Chester</Descritpion>
      <street>1234 Main Street</street>
      <city>Sheboygan</city>
      <state>WI</state>
      <zip>48392</zip>
   </address>
   <address>
      <first-name>Mary</first-name>
      <Descritpion>Hi | This is Mary | Bye</Descritpion>
      <street>283 First Avenue</street>
      <city>Skunk Haven</city>
      <state>MA</state>
      <zip>02718</zip>
   </address>
</addressbook>
于 2012-06-20T12:31:51.557 回答
0

这是另一种方法。

需要注意的一点:此解决方案不维护输出文档的顺序(即,它不<Descritpion>直接在元素下创建新<first-name>元素)。如果这对您很重要,请查看其他提供的解决方案。

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

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

  <!-- TEMPLATE #2 -->
  <xsl:template match="address">
    <xsl:copy>
      <xsl:apply-templates/>
      <Descritpion>
        <xsl:apply-templates select="Descritpion/text()"/>
      </Descritpion>
    </xsl:copy>
  </xsl:template>

  <!-- TEMPLATE #3 -->
  <xsl:template match="Descritpion/text()">
    <xsl:value-of select="." />
    <xsl:if test="position() != last()"> | </xsl:if>    
  </xsl:template>

  <!-- TEMPLATE #4 -->
  <xsl:template match="Descritpion" />
</xsl:stylesheet>

在提供的 XML 文档上提供此信息时:

<?xml version="1.0" encoding="UTF-8"?>
<addressbook>
  <address>
    <first-name>Chester Hasbrouck</first-name>
    <Descritpion>Hi</Descritpion>
    <Descritpion>This is Chester </Descritpion>
    <street>1234 Main Street</street>
    <city>Sheboygan</city>
    <state>WI</state>
    <zip>48392</zip>
  </address>
  <address>
    <first-name>Mary</first-name>
    <Descritpion>Hi</Descritpion>
    <Descritpion>This is Mary </Descritpion>
    <Descritpion>Bye</Descritpion>
    <street>283 First Avenue</street>
    <city>Skunk Haven</city>
    <state>MA</state>
    <zip>02718</zip>
  </address>
</addressbook>

...产生了预期的结果:

<?xml version="1.0" encoding="UTF-8"?><addressbook>
  <address>
    <first-name>Chester Hasbrouck</first-name>
    <street>1234 Main Street</street>
    <city>Sheboygan</city>
    <state>WI</state>
    <zip>48392</zip>
    <Descritpion>Hi | This is Chester </Descritpion>
  </address>
  <address>
    <first-name>Mary</first-name>
    <street>283 First Avenue</street>
    <city>Skunk Haven</city>
    <state>MA</state>
    <zip>02718</zip>
    <Descritpion>Hi | This is Mary  | Bye</Descritpion>
  </address>
</addressbook>

解释:

  • 模板#1: “身份模板”按原样复制所有内容。

  • 模板 #2:此模板按原样复制每个<address>元素,创建一个新<Descritpion>元素,并指示 XSLT 处理器使用来自任何匹配的模板的结果填充该新元素Descritpion/text()

  • 模板#3:该模板处理来自模板#2的结果;特别是,它会从所有旧<Descritpion>元素中复制文本,并在到达最后一个元素之前将 a|放在结果之间。

  • 模板 #4:<Descritpion>此模板从源文档中删除原始元素。

于 2012-06-20T13:59:44.913 回答