使用XSLT连接共享属性值的标记的内容

时间:2017-08-23 18:48:35

标签: xslt xslt-2.0

显然,非常显然,XSLT不是我的事。

Hpwever我有一些XHTML内容,我希望连接它包含的一些自定义标记的内容,但前提是它们共享给定的属性值。

例如,我想转此:

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
   <head>
      <title />
   </head>
   <body>
      <p>
         <mytag myid="0">Don't </mytag>
         <mytag myid="1">concatenate. </mytag>
         Other text
         <mytag myid="2">Text </mytag>
         <mytag myid="2">to </mytag>
         <mytag myid="2">concatenate. </mytag>
         More text
      </p>
   </body>
</html>

进入这个:

<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
   <head>
      <title />
   </head>
   <body>
      <p>
         <mytag myid="0">Don't </mytag>
         <mytag myid="1">concatenate. </mytag>
         Other text
         <mytag myid="2">Text to concatenate. </mytag>
         More text
      </p>
   </body>
</html>

据我所知,我的XSLT:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<xsl:stylesheet xmlns:xhtml="http://www.w3.org/1999/xhtml" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                exclude-result-prefixes="xhtml"
                version="1.0">

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

<!-- Concatenate the contents of custom tags 'mytag'-->
<!-- that share an attribute myid value-->


<xsl:template match="//xhtml:mytag">

    <mytag>

        <xsl:variable name="this-id" select="@myid"/> 

        <xsl:attribute name="myid">
            <xsl:value-of select="$this-id"/>
        </xsl:attribute>

        <xsl:value-of select="."/>

        <xsl:for-each  select="following-sibling::xhtml:mytag[@myid=$this-id]">
            <xsl:value-of select="."/>
        </xsl:for-each>

    </mytag>

</xsl:template>

</xsl:stylesheet>

不过尽量尝试,我无法解决如何停止使用&#39;以下兄弟&#39;选择再次处理。因此,我的输出目前看起来很悲惨:

<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml">
   <head>
      <title/>
   </head>
   <body>
      <p>
         <mytag myid="0">Don't </mytag>
         <mytag myid="1">concatenate. </mytag>
         Other text
         <mytag myid="2">Text to concatenate. </mytag>
         <mytag myid="2">to concatenate. </mytag>
         <mytag myid="2">concatenate. </mytag>
         More text
      </p>
   </body>
</html>

如果感觉像this question,也应该回答我的问题 - 但我太傻了,无法看到它。

帮助?

2 个答案:

答案 0 :(得分:1)

您可以调整当前模板,使其包含'Optimize Macro Speed Application.ScreenUpdating = False Application.EnableEvents = False Application.Calculation = xlCalculationManual Dim wb As Workbook Dim ws As Worksheet Dim FSO As Object, fld As Object, Fil As Object Dim fsoFile As Object Dim fsoFol As Object Dim fsoSubFol As Object Dim folderPath As String, subfolderPath As String, folderName As String, FilePath As String Dim StepOne As String, StepTwo As String, FileName As String, CompareDate As String Dim NextRow As Long Dim FindExistingEntry As Range Set wb = ActiveWorkbook Set ws = wb.Worksheets("Feuil2") With ws .UsedRange.Clear .Cells(1, 1).Value = "Main Folder:" .Cells(1, 2).Value = "File Name:" .Cells(1, 3).Value = "MSG Date:" .Cells(1, 4).Value = "File Name:" .Cells(1, 5).Value = "Approved Date:" .Range("A1:E1").Font.Bold = True End With Application.DisplayAlerts = False With Application.FileDialog(msoFileDialogFolderPicker) .AllowMultiSelect = False If .Show <> -1 Then MsgBox "No folder selected! Exiting script.": Exit Sub folderPath = .SelectedItems(1) End With If Right(folderPath, 1) <> "\" Then folderPath = folderPath + "\" Set FSO = CreateObject("Scripting.FileSystemObject") Set fld = FSO.GetFolder(folderPath) If FSO.FolderExists(fld) Then For Each fsoFol In FSO.GetFolder(folderPath).SubFolders On Error Resume Next subfolderPath = fsoFol & "\Mails" For Each fsoSubFol In FSO.GetFolder(subfolderPath).Files FilePath = fsoSubFol FileName = Split(FilePath, "\")(4) 'Get only "Visa Process--2017-06-07 15h24m00s.MSG" of target file 4 folderName = Split(FilePath, "\")(2) If Mid(FileName, InStrRev(FileName, ".") + 1) = "MSG" Then 'Example: Visa Process--2017-06-07 15h24m00s.MSG If InStr(1, FileName, "Visa Process--", vbTextCompare) <> 0 And Left(FileName, 1) = "V" Then NextRow = ws.Cells(ws.Rows.Count, 2).End(xlUp).Row 'Example: Visa Process--2017-06-07 15h24m00s.MSG StepOne = Split(FileName, "--")(1) 'No "Visa Process--" StepTwo = Mid(StepOne, 1, 10) 'No Time-Stamp 'Make sure to only include the earliest date for each Main Folder "MPCV....." Set FindExistingEntry = ws.Range("A2:A4000").Find(folderName) 'If there is already an entry... If Not FindExistingEntry Is Nothing Then CompareDate = ws.Cells(FindExistingEntry.Row, 3).Value 'Replace old date for that Main Folder if new date is earlier than previous If DateValue(CompareDate) > DateValue(StepTwo) Then ws.Cells(FindExistingEntry.Row, 2).Value = FileName ws.Cells(FindExistingEntry.Row, 3).Value = DateValue(CompareDate) 'Do nothing if Main Folder date is later ElseIf DateValue(CompareDate) < DateValue(StepTwo) Then End If 'If there is no entry for the same Main Folder, simply add a new line ElseIf FindExistingEntry Is Nothing Then ws.Cells(NextRow + 1, 1).Value = folderName ws.Cells(NextRow + 1, 2).Value = FileName ws.Cells(NextRow + 1, 3).Value = DateValue(StepTwo) End If End If 'Do the same for the second document If InStr(1, FileName, "Document signed--", vbTextCompare) <> 0 And Left(FileName, 1) = "D" Then NextRow = ws.Cells(ws.Rows.Count, 2).End(xlUp).Row 'Example: Document signed--2017-06-07 15h24m00s.MSG StepOne = Split(FileName, "--")(1) 'No "Document signed--" StepTwo = Mid(StepOne, 1, 10) 'No Time-Stamp 'Make sure to only include the earliest date for each Main Folder "MPCV....." Set FindExistingEntry = ws.Range("A2:A4000").Find(folderName) 'If there is already an entry... If Not FindExistingEntry Is Nothing Then CompareDate = ws.Cells(FindExistingEntry.Row, 3).Value 'Replace old date for that Main Folder if new date is earlier than previous If DateValue(CompareDate) > DateValue(StepTwo) Then ws.Cells(FindExistingEntry.Row, 4).Value = FileName ws.Cells(FindExistingEntry.Row, 5).Value = DateValue(CompareDate) 'Do nothing if Main Folder date is later ElseIf DateValue(CompareDate) < DateValue(StepTwo) Then End If 'If there is no entry for the same Main Folder, simply add a new line ElseIf FindExistingEntry Is Nothing Then 'ws.Cells(NextRow + 1, 1).Value = folderName 'ws.Cells(NextRow, 4).Value = Filename 'ws.Cells(NextRow, 5).Value = DateValue(StepTwo) End If End If End If Next Next End If 'Message Box when tasks are completed MsgBox "Scan Complete!" 'Reset Macro Optimization Settings Application.EnableEvents = True Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = True ActiveWorkbook.Saved = True ,以检查是否存在具有相同ID的前一个兄弟,以防止多次输出xsl:if

mytag

但是,根据您的要求,如果您的XML看起来像这样,这可能会“失败”

<xsl:stylesheet xmlns:xhtml="http://www.w3.org/1999/xhtml" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                exclude-result-prefixes="xhtml"
                version="1.0">

<xsl:strip-space elements="*" />

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

<xsl:template match="xhtml:mytag">
   <xsl:variable name="this-id" select="@myid"/> 
   <xsl:if test="not(preceding-sibling::xhtml:mytag[@myid = $this-id])">
      <xsl:copy>
         <xsl:attribute name="myid">
            <xsl:value-of select="$this-id"/>
         </xsl:attribute>
         <xsl:value-of select="."/>
         <xsl:for-each select="following-sibling::xhtml:mytag[@myid=$this-id]">
            <xsl:value-of select="."/>
         </xsl:for-each>
      </xsl:copy>
   </xsl:if>
</xsl:template>
</xsl:stylesheet>

给定的XSLT会生成这个......

  <p>
     <mytag myid="0">Don't </mytag>
     <mytag myid="1">concatenate. </mytag>
     Other text
     <mytag myid="2">Text </mytag>
     <mytag myid="2">to </mytag>
     <mytag myid="2">concatenate. </mytag>
     More text
     <mytag myid="1">Concatenate separately. </mytag>
  </p>

这是因为以下兄弟轴获得所有后续兄弟,而不仅仅是当前节点之后的兄弟。

如果你真的想要这个......

<body xmlns="http://www.w3.org/1999/xhtml">
   <p>
      <mytag myid="0">Don't </mytag>
      <mytag myid="1">concatenate. Concatenate separately. </mytag>
         Other text
         <mytag myid="2">Text to concatenate. </mytag>
         More text
         </p>
</body>

然后你必须一次看一下以下的兄弟姐妹。试试这个XSLT

<body xmlns="http://www.w3.org/1999/xhtml">
<p>
<mytag myid="0">Don't </mytag>
<mytag myid="1">concatenate. </mytag>
         Other text
         <mytag myid="2">Text to concatenate. </mytag>
         More text
         <mytag myid="1">Concatenate separately. </mytag>
</p>
</body>

答案 1 :(得分:0)

这可以在XSLT 2.0中使用

非常简单地实现
<xsl:template match="p">
  <xsl:for-each-group select="mytag" group-adjacent="@myid">
    <mytag myid="{current-grouping-key()}">
      <xsl:value-of select="string-join(current-group(), '')"/>
    </mytag>
  </xsl:for-each-group>
</xsl:template>