BIEŻĄCY XML:
<?xml version="1.0"?>
<form1>
<page1>
<first_name></first_name>
<last_name></last_name>
.
.
</page1>
<page2>
<address></address>
<phone_number></phone_number>
.
.
</page2>
<page3>
<company_name></company_name>
<job_title></job_title>
.
.
</page3>
</form1>
ŻĄDANY XML - chcę scalić wszystkie elementy podrzędne i zmienić nazwę rodzica:
<?xml version="1.0"?>
<form>
<page>
<first_name></first_name>
<last_name></last_name>
.
.
<address></address>
<phone_number></phone_number>
.
.
<company_name></company_name>
<job_title></job_title>
.
.
</page>
</form>
wtedy, ponieważ mam tysiące plików XML z rozszerzeniemniektóre nieznane elementy, chcę znaleźć je wszystkie przed zbiorczym zaimportowaniem XML do bazy danych Access, ponieważ wszelkie nowe elementy w kolejnych plikach zostaną usunięte, jeśli nie są zdefiniowane w schemacie.
nie wszystkie elementy potomne są znane. nie wszystkie nazwy plików są znane.
Jak więc mogę sprawdzić wszystkie pliki pod kątem wszystkich elementów, wypełnić tabelę Access nimi wszystkimi, a następnie zbiorczo zaimportować wszystkie rekordy XML, aby dopasować je do żądanego schematu, jak pokazano powyżej?
EDYTOWAĆ:
ok, rozumiem - nie ma atrybutów. miałem na myśli wszystkie elementy potomne. dzięki za wskazanie tego Oded, zaktualizowałem pytanie o poprawki.
to jest kod VBA, którego używam w programie Access do zbiorczego importowania plików:
Private Sub cmdImport_Click()
Dim strFile As String "Filename
Dim strFileList() As String "File Array
Dim intFile As Integer "File Number
Dim strPath As String " Path to file folder
strPath = "C:UsersMainDesktopXML-files"
strFile = Dir(strPath & "*.XML")
While strFile <> ""
"add files to the list
intFile = intFile + 1
ReDim Preserve strFileList(1 To intFile)
strFileList(intFile) = strFile
strFile = Dir()
Wend
"see if any files were found
If intFile = 0 Then
MsgBox "No files found"
Exit Sub
End If
"cycle through the list of files
For intFile = 1 To UBound(strFileList)
Application.ImportXML strPath & strFileList(intFile), acAppendData
Next intFile
MsgBox "Import Completed"
End Sub
mogę użyć arkusza stylów, aby przekształcić XML w taki sposób:
For intFile = 1 To UBound(strFileList)
Application.TransformXML strPath & strFileList(intFile), _
"C:UsersMainDesktopstylesheet2.xslt", _
"C:UsersMainDesktoptemp.xml", True
Application.ImportXML "C:UsersMainDesktoptemp.xml", acAppendData
Next intFile
MsgBox "Import Completed"
End Sub
jednak nie łączy wszystkich elementów pliku w jedną tabelę. brakuje mi czegoś czy muszę zapisać listę zmiennych? lub utworzyć identyfikatory atrybutów?
EDYTOWAĆ: Z komentarzy
moje nazwy plików to 1.xml, 2.xml, 3.xml, 4.xml, itp. Ale jak powiedziałem, mają tysiące
Odpowiedzi:
0 dla odpowiedzi № 1Załóżmy, że te dokumenty wejściowe:
1.xml
<form1>
<page1>
<first_name>D</first_name>
<last_name>E</last_name>
</page1>
<page2>
<address>F</address>
<phone_number>1</phone_number>
</page2>
<page3>
<company_name>G</company_name>
</page3>
</form1>
2.xml
<form2>
<page1>
<first_name>A</first_name>
</page1>
<page2>
<address>B</address>
</page2>
<page3>
<company_name>C</company_name>
<job_title>H</job_title>
</page3>
</form2>
Ten arkusz stylów:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kElementByName" match="/*/*/*" use="name()"/>
<xsl:param name="pMaxFileNumber" select="2"/>
<xsl:template match="/">
<xsl:variable name="vFieldsNames">
<xsl:call-template name="names">
<xsl:with-param name="pFrom" select="1"/>
<xsl:with-param name="pTo" select="$pMaxFileNumber"/>
<xsl:with-param name="pFieldsNames" select=""|""/>
</xsl:call-template>
</xsl:variable>
<form>
<xsl:call-template name="merge">
<xsl:with-param name="pFrom" select="1"/>
<xsl:with-param name="pTo" select="$pMaxFileNumber"/>
<xsl:with-param name="pFieldsNames" select="$vFieldsNames"/>
</xsl:call-template>
</form>
</xsl:template>
<xsl:template name="names">
<xsl:param name="pFrom"/>
<xsl:param name="pTo"/>
<xsl:param name="pFieldsNames"/>
<xsl:choose>
<xsl:when test="$pFrom = $pTo">
<xsl:value-of select="$pFieldsNames"/>
<xsl:apply-templates
select="document(concat($pFrom,".xml"),/)/*/*/*
[count(.|key("kElementByName",
name())[1])=1]
[not(contains($pFieldsNames,
concat("|",name(),"|")))]"
mode="names"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="vNewTop"
select="floor(($pTo - $pFrom) div 2) + $pFrom"/>
<xsl:variable name="vNewFieldsNames">
<xsl:call-template name="names">
<xsl:with-param name="pFrom" select="$pFrom"/>
<xsl:with-param name="pTo" select="$vNewTop"/>
<xsl:with-param name="pFieldsNames"
select="$pFieldsNames"/>
</xsl:call-template>
</xsl:variable>
<xsl:call-template name="names">
<xsl:with-param name="pFrom" select="$vNewTop + 1"/>
<xsl:with-param name="pTo" select="$pTo"/>
<xsl:with-param name="pFieldsNames"
select="$vNewFieldsNames"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="merge">
<xsl:param name="pFrom"/>
<xsl:param name="pTo"/>
<xsl:param name="pFieldsNames"/>
<xsl:choose>
<xsl:when test="$pFrom = $pTo">
<page>
<xsl:apply-templates
select="document(concat($pFrom,".xml"),/)/*/*[1]/*[1]">
<xsl:with-param name="pFieldsNames"
select="$pFieldsNames"/>
</xsl:apply-templates>
</page>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="vNewTop"
select="floor(($pTo - $pFrom) div 2) + $pFrom"/>
<xsl:call-template name="merge">
<xsl:with-param name="pFrom" select="$pFrom"/>
<xsl:with-param name="pTo" select="$vNewTop"/>
<xsl:with-param name="pFieldsNames" select="$pFieldsNames"/>
</xsl:call-template>
<xsl:call-template name="merge">
<xsl:with-param name="pFrom" select="$vNewTop + 1"/>
<xsl:with-param name="pTo" select="$pTo"/>
<xsl:with-param name="pFieldsNames" select="$pFieldsNames"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="/*/*">
<xsl:param name="pFieldsNames"/>
<xsl:apply-templates select="*[1]">
<xsl:with-param name="pFieldsNames" select="$pFieldsNames"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="/*/*/*" name="copy">
<xsl:param name="pFieldsNames"/>
<xsl:copy>
<xsl:value-of select="."/>
</xsl:copy>
<xsl:variable name="vName" select="concat("|",name(),"|")"/>
<xsl:apply-templates select="following::*[1]">
<xsl:with-param name="pFieldsNames"
select="concat(substring-before($pFieldsNames,
$vName),
"|",
substring-after($pFieldsNames,
$vName))"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="/*/*[last()]/*[last()]">
<xsl:param name="pFieldsNames"/>
<xsl:call-template name="copy"/>
<xsl:variable name="vName" select="concat("|",name(),"|")"/>
<xsl:call-template name="empty">
<xsl:with-param name="pFieldsNames"
select="substring(
concat(substring-before($pFieldsNames,
$vName),
"|",
substring-after($pFieldsNames,
$vName)),
2)"/>
</xsl:call-template>
</xsl:template>
<xsl:template match="/*/*/*" mode="names">
<xsl:value-of select="concat(name(),"|")"/>
</xsl:template>
<xsl:template name="empty">
<xsl:param name="pFieldsNames"/>
<xsl:if test="$pFieldsNames!=""">
<xsl:element name="{substring-before($pFieldsNames,"|")}"/>
<xsl:call-template name="empty">
<xsl:with-param name="pFieldsNames"
select="substring-after($pFieldsNames,"|")"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Wydajność:
<form>
<page>
<first_name>D</first_name>
<last_name>E</last_name>
<address>F</address>
<phone_number>1</phone_number>
<company_name>G</company_name>
<job_title />
</page>
<page>
<first_name>A</first_name>
<address>B</address>
<company_name>C</company_name>
<job_title>H</job_title>
<last_name />
<phone_number />
</page>
</form>
Uwaga: Jeśli to wysadzi twoją pamięć, musisz podzielić to na dwa arkusze stylów: najpierw wypisz imiona; po drugie, scal. Jeśli nie możesz przekazać parametru Application.TransformXML
, maksymalna liczba plików jest ustalona. Ponadto nie może być żadnej dziury: jeśli maksymalna liczba plików to 3, 2.xml
nie można przegapić (to dlatego, że fn:document
zgłasza błąd)
EDYTOWAĆ: Dla transformacji dwuprzebiegowej.
Ten arkusz stylów z dowolnymi danymi wejściowymi (nie używane):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="pMaxFileNumber" select="2"/>
<xsl:template match="/">
<form>
<xsl:call-template name="copy">
<xsl:with-param name="pFrom" select="1"/>
<xsl:with-param name="pTo" select="$pMaxFileNumber"/>
</xsl:call-template>
</form>
</xsl:template>
<xsl:template name="copy">
<xsl:param name="pFrom"/>
<xsl:param name="pTo"/>
<xsl:choose>
<xsl:when test="$pFrom = $pTo">
<page>
<xsl:copy-of
select="document(concat($pFrom,".xml"),/)/*/*/*"/>
</page>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="vMiddle"
select="floor(($pTo - $pFrom) div 2) + $pFrom"/>
<xsl:call-template name="copy">
<xsl:with-param name="pFrom" select="$pFrom"/>
<xsl:with-param name="pTo" select="$vMiddle"/>
</xsl:call-template>
<xsl:call-template name="copy">
<xsl:with-param name="pFrom" select="$vMiddle + 1"/>
<xsl:with-param name="pTo" select="$pTo"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Wydajność:
<form>
<page>
<first_name>D</first_name>
<last_name>E</last_name>
<address>F</address>
<phone_number>1</phone_number>
<company_name>G</company_name>
</page>
<page>
<first_name>A</first_name>
<address>B</address>
<company_name>C</company_name>
<job_title>H</job_title>
</page>
</form>
A ten arkusz stylów:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kElementByName" match="/*/*/*" use="name()"/>
<xsl:variable name="vElements"
select="/*/*/*[count(.|key("kElementByName",name())[1])=1]"/>
<xsl:template match="form">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="page">
<xsl:copy>
<xsl:apply-templates select="$vElements">
<xsl:with-param name="pContext" select="."/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="/*/*/*">
<xsl:param name="pContext"/>
<xsl:element name="{name()}">
<xsl:value-of select="$pContext/*[name()=name(current())]"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Z wyjściem wstecznym jako wejściem, wynik:
<form>
<page>
<first_name>D</first_name>
<last_name>E</last_name>
<address>F</address>
<phone_number>1</phone_number>
<company_name>G</company_name>
<job_title></job_title>
</page>
<page>
<first_name>A</first_name>
<last_name></last_name>
<address>B</address>
<phone_number></phone_number>
<company_name>C</company_name>
<job_title>H</job_title>
</page>
</form>
0 dla odpowiedzi nr 2
Ten arkusz stylów tworzy opisany przez Ciebie wynik.
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" />
<xsl:template match="/">
<!--generate standard document element and it"s child element-->
<form>
<page>
<!--Apply templates to children of document element"s, child element"s, children-->
<xsl:apply-templates select="/*/*/node()" />
</page>
</form>
</xsl:template>
<!--Identity template copies all content forward-->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Jeśli chcesz tylko skopiować elementy pod elementami strony, a nie jakikolwiek węzeł () (element, tekst, komentarz lub instrukcja przetwarzania), możesz zmienić XPATH z: /*/*/node()
do: /*/*/*
0 dla odpowiedzi № 3
Jeśli naprawdę chcesz po prostu Kopiuj cała zawartość pliku page{N}
pierwiastków, to ta transformacja jest prawdopodobnie najkrótsza:
<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="/">
<form>
<page>
<xsl:copy-of select="/*/*/node()"/>
</page>
</form>
</xsl:template>
</xsl:stylesheet>