【问题标题】:XSLT merge two XML files/templates, Getting extra information appended outside the desired tagXSLT 合并两个 XML 文件/模板,获取附加在所需标记之外的额外信息
【发布时间】:2015-08-11 03:06:32
【问题描述】:

我是 xml 和 XSLT 的新手。我正在尝试基于 id 标记值合并两个 xml 文件。我正在使用 xslt 1.0 版

这是我的 file1.xml

<?xml version='1.0' encoding='UTF-8'?>
<people-appointment-data>
<person-data>        
    <id>12345</id>
    <first-name>John</first-name>
    <last-name>Hewitt</last-name>       
    <appointments>
      <appointment>
        <code>1</code>
        <pass>1</pass>
        <states>
            <state>IL</state>
            <state>IN</state>
        </states>
     </appointment>
      <appointment>
        <code>2</code>
        <pass>2</pass>
        <states>
            <state>NV</state>
            <state>CA</state>
        </states>
     </appointment>
</appointments>
</person-data>
<person-data>        
<id>67890</id>
<first-name>Mike</first-name>
<last-name>Hewitt</last-name>       
<appointments>
    <appointment>
        <code>5</code>
        <pass>5</pass>
        <states>
            <state>AK</state>
            <state>MA</state>
        </states>
    </appointment>
</appointments>
</person-data>
</people-appointment-data>

这是我的 file2.xml

<?xml version='1.0' encoding='UTF-8'?>
<people-appointment-data>
<person-data>        
    <id>12345</id>
    <first-name>John</first-name>  
    <last-name>Hewitt</last-name>     
    <appointments>
      <appointment>
        <code>3</code>
        <pass>3</pass>
        <states>
            <state>IL</state>
            <state>IN</state>
        </states>
     </appointment>
      <appointment>
        <code>4</code>
        <pass>4</pass>
        <states>
            <state>NV</state>
            <state>CA</state>
        </states>
     </appointment>
  </appointments> 
</person-data>
<person-data>        
<id>67890</id>
<first-name>Mike</first-name>    
<last-name>Hewitt</last-name>   
<appointments>
    <appointment>
        <code>6</code>
        <pass>6</pass>
        <states>
            <state>AK</state>
            <state>MA</state>
        </states>
    </appointment>
</appointments>
</person-data>
</people-appointment-data>

这是我正在使用的 XSLT。

<?xml version="1.0"?>
<xsl:stylesheet version="1.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:param name="lookup-document" select="document('file2.xml')"/>
 <xsl:key name="pdata" match="person-data" use="id" />

<xsl:template match="/">
<people-data>
    <xsl:for-each select="people-appointment-data/person-data">
        <person-data>
            <xsl:variable name="id" select="id" />
            <xsl:copy-of select="*"/>
            <!--  switch context to lookup-document in order to use              the key -->
              <xsl:for-each select="$lookup-document">
                  <xsl:copy-of select="key('pdata', $id)/appointments/appointment"/>
              </xsl:for-each> 
          </person-data>
      </xsl:for-each>
  </people-data>
  </xsl:template>

</xsl:stylesheet>

这就是我得到错误输出的方式,发生的事情是所有appointment 都被附加到appointments 标记下方,但我想要实现的是实际上只是复制所有@ 987654327@ 与第一个 appointments 标签内的 id 标签匹配:

<?xml version="1.0" encoding="UTF-8"?>
<people-data>
<person-data>
    <id>12345</id>
    <first-name>John</first-name>
    <last-name>Hewitt</last-name>
    <appointments>
        <appointment>
            <code>1</code>
            <pass>1</pass>
            <states>
                <state>IL</state>
                <state>IN</state>
            </states>
        </appointment>
        <appointment>
            <code>2</code>
            <pass>2</pass>
            <states>
                <state>NV</state>
                <state>CA</state>
            </states>
        </appointment>
    </appointments>
    <appointment>
        <code>1</code>
        <pass>1</pass>
        <states>
            <state>IL</state>
            <state>IN</state>
        </states>
    </appointment>
    <appointment>
        <code>2</code>
        <pass>2</pass>
        <states>
            <state>NV</state>
            <state>CA</state>
        </states>
    </appointment>
    <appointment>
        <code>3</code>
        <pass>3</pass>
        <states>
            <state>IL</state>
            <state>IN</state>
        </states>
    </appointment>
    <appointment>
        <code>4</code>
        <pass>4</pass>
        <states>
            <state>NV</state>
            <state>CA</state>
        </states>
    </appointment>
</person-data>
<person-data>
    <id>67890</id>
    <first-name>Mike</first-name>
    <last-name>Hewitt</last-name>
    <appointments>
        <appointment>
            <code>5</code>
            <pass>5</pass>
            <states>
                <state>AK</state>
                <state>MA</state>
            </states>
        </appointment>
    </appointments>
    <appointment>
        <code>5</code>
        <pass>5</pass>
        <states>
            <state>AK</state>
            <state>MA</state>
        </states>
    </appointment>
    <appointment>
        <code>6</code>
        <pass>6</pass>
        <states>
            <state>AK</state>
            <state>MA</state>
        </states>
    </appointment>
</person-data>
</people-data>

这就是我想要的输出。我不明白我做错了什么。如果有人可以指导我。

预期输出:

<?xml version="1.0" encoding="UTF-8"?>
<people-data>
<person-data>
    <id>12345</id>
    <first-name>John</first-name>
    <last-name>Hewitt</last-name>
    <appointments>
        <appointment>
            <code>1</code>
            <pass>1</pass>
            <states>
                <state>IL</state>
                <state>IN</state>
            </states>
        </appointment>
        <appointment>
            <code>2</code>
            <pass>2</pass>
            <states>
                <state>NV</state>
                <state>CA</state>
            </states>
        </appointment>
        <appointment>
            <code>3</code>
            <pass>3</pass>
            <states>
                <state>IL</state>
                <state>IN</state>
            </states>
        </appointment>
        <appointment>
            <code>4</code>
            <pass>4</pass>
            <states>
                <state>NV</state>
                <state>CA</state>
            </states>
        </appointment>
    </appointments>
</person-data>
<person-data>
    <id>67890</id>
    <first-name>Mike</first-name>
    <last-name>Hewitt</last-name>
    <appointments>
        <appointment>
            <code>5</code>
            <pass>5</pass>
            <states>
                <state>AK</state>
                <state>MA</state>
            </states>
        </appointment>
        <appointment>
            <code>6</code>
            <pass>6</pass>
            <states>
                <state>AK</state>
                <state>MA</state>
            </states>
        </appointment>
    </appointments>
</person-data>
</people-data>

非常感谢您的帮助。

【问题讨论】:

    标签: java xml xslt xslt-1.0


    【解决方案1】:

    发生这种情况是因为您正在从第一个文件中复制“people-appointment-data/person-data”中的所有内容。试试这样的:

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.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:param name="lookup-document" select="document('file2.xml')"/>
     <xsl:key name="pdata" match="person-data" use="id" />
    
    <xsl:template match="/">
    <people-data>
        <xsl:for-each select="people-appointment-data/person-data">
            <person-data>
                <xsl:variable name="id" select="id" />
                <id><xsl:value-of select="$id"/></id>
                <firstname><xsl:value-of select="firstname"/></firstname>
                <lastname><xsl:value-of select="lastname"/></lastname> 
                <appointments>
                  <xsl:for-each select="appointments/appointment">
                      <xsl:copy-of select="*"/>
                  </xsl:for-each>
                  <!--  switch context to lookup-document in order to use the key -->
                  <xsl:for-each select="$lookup-document">
                      <xsl:copy-of select="key('pdata', $id)/appointments/appointment"/>
                  </xsl:for-each>
                </appointments> 
              </person-data>
          </xsl:for-each>
      </people-data>
      </xsl:template>
    
    </xsl:stylesheet>
    

    我还没有测试过,所以如果您需要进行相同的调整,请不要与我争论。然而,这是总体思路。

    如果您想避免手动复制节点,那么您需要一个功能来复制除 appointments 节点之外的任何节点。你可以在这里找到关于这个的讨论:

    XSL: Select all text in a node, except nodes of a certain type

    请注意,这样做您将能够一次复制所有 appointments 前面的节点。完成后,您可以按照我已经建议的方式进行操作。

    【讨论】:

    • 我知道这是解决问题的一种方法。但在我的xml 数据中,我有更多tags 参考此问题中给出的数据,例如firstnamelastnameageaddress....etc 输入所有这些数据将是一个非常大的 XSLT。我相信你可以通过复制所有数据来做到这一点。我只是不明白如何在appointments 标签内附加数据
    • 我添加了一个可能对您有帮助的讨论链接。
    【解决方案2】:

    您可以使用身份模板,而不是依赖xsl:copy-of 来复制现有节点

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

    那么你只需要为你想要转换的节点写一个模板。在这种情况下,您将转换第一个文档中的 appointments 元素,因为您将添加来自第二个文档的子 appointment 元素。因此,您将拥有这样的模板:

    <xsl:template match="appointments">
        <xsl:variable name="id" select="../id" />
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
            <xsl:for-each select="$lookup-document">
                <xsl:apply-templates select="key('pdata', $id)/appointments/appointment"/>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
    

    这只是复制现有的appointments 元素以及第一个文档中的所有子节点,然后使用键从第二个文档中添加appointment 节点。

    试试这个 XSLT

    <xsl:stylesheet version="1.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:param name="lookup-document" select="document('file2.xml')"/>
        <xsl:key name="pdata" match="person-data" use="id" />
    
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="appointments">
            <xsl:variable name="id" select="../id" />
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
                <xsl:for-each select="$lookup-document">
                    <xsl:apply-templates select="key('pdata', $id)/appointments/appointment"/>
                </xsl:for-each>
            </xsl:copy>
        </xsl:template>
    </xsl:stylesheet>
    

    【讨论】:

    • 我尝试了您推荐的解决方案,但没有按预期工作。它确实将所有appointment 复制到appointments 标签下的合并文件中,但它也从第一个文件中复制了appointment 两次。你能告诉我如何将这些信息复制一次吗
    • 我从&lt;xsl:template match="appointments"&gt; 中删除了这一行 已删除行 --> &lt;xsl:apply-templates select="@*|node()"/&gt; 现在可以了,我猜它复制了两次所以不需要应用身份模板。这是正确的吗?
    • 当我尝试测试它时,它产生了您问题中显示的预期输出,所以我不确定发生了什么。您是否确定在答案中使用了 XLST,或者您是否先对其进行了一些其他更改?
    • 我正在使用此答案中提供的那个。我以这种方式复制了两次appointment。因此对于 file1.xml,您将在合并中有重复的 appointment 标签
    猜你喜欢
    • 2012-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-02
    相关资源
    最近更新 更多