将具有不同XML文件的子元素的特定元素复制到输出文件中并保持整体结构

时间:2017-10-12 15:33:15

标签: xml xslt xslt-2.0

我的问题是我有不同的XML文件具有相同的结构,我想提取这些输入文件的某些元素,并生成一个新的输出文档,其中包含的摘录。

所以,让我们弄清楚:-)(下面的示例链接)

input1.xml:

<?xml version="1.0" encoding="utf-16"?>
<msg:Msg xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:msg="http://some/msg/namespace/2.0">
       <msg:preserve1>
          <msg:preserve2>
             <msg:preserve3>Preserve that</msg:preserve3>
          </msg:preserve2>
          <msg:Logon/>
       </msg:preserve1>
       <msg:Body>
          <msg:Req>
             <msg:Dta>
                <ResponseRowset xmlns:msg="http://some/msg/namespace/1.1"
                                xmlns="http://defaultnamespace">
                   <ResponseRow>
                      <ArticleNo>123</ArticleNo>
                      <List>02</List>
                      <Flag>2</Flag>
                   </ResponseRow>
                   <ResponseRow>
                      <ArticleNo>234</ArticleNo>
                      <List>02</List>
                      <Flag>3</Flag>
                   </ResponseRow>
                   <ResponseRow>
                      <ArticleNo>345</ArticleNo>
                      <List>03</List>
                      <Flag>3</Flag>
                   </ResponseRow>
                </ResponseRowset>
             </msg:Dta>
          </msg:Req>
       </msg:Body>
    </msg:Msg>

input2.xml

<?xml version="1.0" encoding="utf-16"?>
<msg:Msg xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:msg="http://some/msg/namespace/2.0">
   <msg:preserve1>
      <msg:preserve2>
         <msg:preserve3>Preserve that</msg:preserve3>
      </msg:preserve2>
      <msg:Logon/>
   </msg:preserve1>
   <msg:Body>
      <msg:Req>
         <msg:Dta>
            <ResponseRowset xmlns:msg="http://some/msg/namespace/1.1"
                            xmlns="http://defaultnamespace">
               <ResponseRow>
                  <ArticleNo>3423</ArticleNo>
                  <List>03</List>
                  <Flag>3</Flag>
               </ResponseRow>
               <ResponseRow>
                  <ArticleNo>234</ArticleNo>
                  <List>05</List>
                  <Flag>4</Flag>
               </ResponseRow>
               <ResponseRow>
                  <ArticleNo>234</ArticleNo>
                  <List>01</List>
                  <Flag>4</Flag>
               </ResponseRow>
               <ResponseRow>
                  <ArticleNo>456</ArticleNo>
                  <List>03</List>
                  <Flag>3</Flag>
               </ResponseRow>
            </ResponseRowset>
         </msg:Dta>
      </msg:Req>
   </msg:Body>
</msg:Msg>

现在,如果<ResponseRow>标记包含指定的数字之一,我想将所有<ArticleNo>标记及其子标记复制到新文件中。

让我们说我想拥有所有ResponseRow元素,其中ArticleNo是&#39; 234&#39;或者&#39; 456&#39;

我的预期结果应为

<?xml version="1.0" encoding="utf-16"?>
<msg:Msg xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:msg="http://some/msg/namespace/2.0">
   <msg:preserve1>
      <msg:preserve2>
         <msg:preserve3>Preserve that</msg:preserve3>
      </msg:preserve2>
      <msg:Logon/>
   </msg:preserve1>
   <msg:Body>
      <msg:Req>
         <msg:Dta>
            <ResponseRowset xmlns:msg="http://some/msg/namespace/1.1" xmlns="http://defaultnamespace">
               <ResponseRow>
                  <ArticleNo>234</ArticleNo>
                  <List>02</List>
                  <Flag>3</Flag>
               </ResponseRow>
               <ResponseRow>
                  <ArticleNo>234</ArticleNo>
                  <List>05</List>
                  <Flag>4</Flag>
               </ResponseRow>
               <ResponseRow>
                  <ArticleNo>456</ArticleNo>
                  <List>03</List>
                  <Flag>3</Flag>
               </ResponseRow>
               <ResponseRow>
                  <ArticleNo>234</ArticleNo>
                  <List>05</List>
                  <Flag>4</Flag>
               </ResponseRow>
               <ResponseRow>
                  <ArticleNo>456</ArticleNo>
                  <List>03</List>
                  <Flag>3</Flag>
               </ResponseRow>
            </ResponseRowset>
         </msg:Dta>
      </msg:Req>
   </msg:Body>
</msg:Msg>

如果我在一个文件中包含所有内容,则使用以下xsl文件:

<xsl:stylesheet version="2.0" 
    xmlns:msg="http://some/msg/namespace/2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:output method="xml" indent="yes" encoding="utf-16"/>
 <xsl:strip-space elements="*"/>

    <xsl:template match="*" xpath-default-namespace="http://defaultnamespace">
            <xsl:copy>
                <xsl:apply-templates select="node() except ResponseRow[ArticleNo!='234' and ArticleNo!='456']"/>
            </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

但我无法使用两个或更多输入文件。这是&#34; one-file&#34;的链接。例如:http://xsltransform.net/3NzcBsK/33

我不喜欢的是像 ResponseRow [ArticleNo!=&#39; 234&#39;和ArticleNo!=&#39; 456&#39;] 因为我会列出10个不同的文章编号,但这不是我的主要关注点。

请注意,名称空间看起来很奇怪,但由于文件是由某个供应商生成的,因此我不会对此产生影响

如果你可以帮我解决这个问题会很好。

2 个答案:

答案 0 :(得分:1)

*上的匹配对我来说很奇怪,对于第二个文件和那些文章编号,我会定义一个全局参数

<xsl:param name="articles-to-copy" as="xs:string*" select="'234', '456'"/>

然后匹配

<xsl:template match="ResponseRowset" xpath-default-namespace="http://defaultnamespace">
        <xsl:copy>
            <xsl:apply-templates select="(ResponseRow , doc('file2.xml')//ResponseRow)[ArticleNo = $articles-to-copy]"/>
        </xsl:copy>
</xsl:template>

当然伴随着身份转换模板

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

答案 1 :(得分:0)

非常感谢Martin Honnen指出要走的路,唯一不起作用的是参数值。

再次感谢你,我的最终解决方案是:

<xsl:param name="articles-to-copy" select="('234', '456')" />

<xsl:variable name="pricelist01" select="document('input1.xml')"/>
<xsl:variable name="pricelist02" select="document('input2.xml')"/>

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

<xsl:template match="ResponseRowset" xpath-default-namespace="http://defaultnamespace">
    <xsl:copy>
        <xsl:apply-templates select="(ResponseRow, $pricelist01//ResponseRow, $pricelist02//ResponseRow)[StockCode=$articles-to-copy]"/>
    </xsl:copy>
</xsl:template>

这是在另外两个文件中进行查找。我做的唯一更改是从标记中删除 as =“xs:string”。看起来真的很不错: - )