可以使用 XSLT 展开 XML 吗?

Unfolding XML with XSLT possible?

这是我要转换的 XML 文档:

<?xml version="1.0" encoding="utf-8"?>
<batchResponse>
  <searchResponse>
    <searchResultEntry dn="uid=Massan Jill">
      <attr name="cn">
        <value>Massan, Jill</value>
      </attr>
      <attr name="userAccount">
        <value>ABC1234567</value>
        <value>DEF1234567</value>
      </attr>
    </searchResultEntry>
  </searchResponse>
</batchResponse>

这是我为转换创建的 xslt:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <entry>
      <xsl:for-each select="batchResponse/searchResponse/searchResultEntry">
        <xsl:if test="@dn!='' and contains(@dn, 'uid=')">                 
          <import>      
            <cn>
              <xsl:value-of select="attr[@name='cn']/value"/>
            </cn>
            <userAccount>
              <xsl:value-of select="attr[@name='userAccount']/value"/>
            </userAccount>
          </import>    
        </xsl:if>
      </xsl:for-each>
    </entry>
  </xsl:template>
</xsl:stylesheet>

这是转换后的 XML:

<?xml version="1.0" encoding="UTF-8"?>
<entry>
   <import>
      <cn>Massan, Jill</cn>
      <userAccount>ABC1234567</userAccount>
   </import>
</entry>

我的问题是,原始 XML 数据包含 "userAccount" 的多个值,并且转换后的 XML 应该通过将此类数据展开到多个导入条目来反映这一点:

<?xml version="1.0" encoding="UTF-8"?>
<entry>
   <import>
      <cn>Massan, Jill</cn>
      <userAccount>ABC1234567</userAccount>
   </import>
   <import>
     <cn>Massan, Jill</cn>
     <userAccount>DEF1234567</userAccount>
   </import>
</entry>

这甚至可以用 xslt 实现吗?如果可以,怎么做?

您可以使用 xsl:for-each 到 select 每个 "user account" 条目,然后为每个

创建一个 import 记录

试试这个 XSLT

<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" />
  <xsl:template match="/">
    <entry>
      <xsl:for-each select="batchResponse/searchResponse/searchResultEntry">
        <xsl:if test="@dn!='' and contains(@dn, 'uid=')">                 
          <xsl:for-each select="attr[@name='userAccount']/value">
          <import>      
            <cn>
              <xsl:value-of select="../../attr[@name='cn']/value"/>
            </cn>
            <userAccount>
              <xsl:value-of select="."/>
            </userAccount>
          </import>    
          </xsl:for-each>
        </xsl:if>
      </xsl:for-each>
    </entry>
  </xsl:template>
</xsl:stylesheet>

注意表达式 <xsl:value-of select="../../attr[@name='cn']/value"/> 以获取用户名。这是因为你定位在value元素上,所以需要返回层级向上获取用户名(..表示获取当前节点的父节点)。

实际上,您可以将两个 xsl:for-each 语句和 xsl:if 合并为一个,以简化操作。也试试这个 XSLT

<xsl:stylesheet version="1.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" />
  <xsl:template match="/">
    <entry>
      <xsl:for-each select="batchResponse/searchResponse/searchResultEntry[@dn!='' and contains(@dn, 'uid=')]/attr[@name='userAccount']/value">
      <import>      
        <cn>
          <xsl:value-of select="../../attr[@name='cn']/value"/>
        </cn>
        <userAccount>
          <xsl:value-of select="."/>
        </userAccount>
      </import>    
      </xsl:for-each>
    </entry>
  </xsl:template>
</xsl:stylesheet>