I'm trying to get a value from a node in a .jdf file.
It gives us an error
object required: 'curNode'
in line no. 13 - inputFolder = curNode.getAttribute("Amount")
We don't really know what to do... any help please?
Thank you
'creates the msxml object
Set xmlDoc = CreateObject("Msxml2.DOMDocument.6.0")
Dim xmlDataPath,retVal
xmlDataPath = "C:\Users\liatte\Desktop\Aviv Omer Neta\JDFs to Txt\a.jdf"
'load the xml data of the script
retVal=xmlDoc.load(xmlDataPath)
'get input folder
Set curNode = xmlDoc.selectSingleNode("//JDF/ResourceLinkPool/ComponentLink")
Dim inputFolder
inputFolder = curNode.getAttribute("Amount")
To deal with the error, check
If curNode Is Nothing Then
...
Else
Dim inputFolder
...
End If
Obviously your assumptions (XPath expression) about the source file are wrong, when selectSingleNode() fails.
If an XPath expression like //JDF/ResourceLinkPool/ComponentLink does not select elements in your input document then it is likely that you are processing a document which uses namespaces, see http://en.wikipedia.org/wiki/XML_namespaces.
With XPath 1.0 a path like /foo/bar selects bar child elements of foo elements in no namespace while with an XML document of the form
<foo xmlns="http://example.com/ns1">
<bar>baz</bar>
</foo>
the elements are in the namespace http://example.com/ns1.
With your sample there is probably a default namespace declaration (e.g. xmlns="http://www.CIP4.org/JDFSchema_1_1") which requires you to change your XPath expressions by defining a prefix for the namespace e.g.
xmlDoc.setProperty "SelectionNamespaces", "xmlns:jdf='http://www.CIP4.org/JDFSchema_1_1'"
and using it:
Set curNode = xmlDoc.selectSingleNode("//jdf:JDF/jdf:ResourceLinkPool/jdf:ComponentLink")
Documentation for MSXML is at http://msdn.microsoft.com/en-us/library/windows/desktop/ms756048%28v=vs.85%29.aspx.
Related
Given a Column A in Excel with multiple cells containing ISBN (book id) values, I want my VBA macro to loop through each of them and, for each one, parse an online XML file that is unique to that ISBN and put the corresponding book title in Column B.
For example, if A1 contains 1931498717, I should parse this XML and grab the title "Don't think of an elephant! : know your values and frame the debate : the essential guide for progressives" and put that in B1.
Here is a sample of the XML file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<classify xmlns="http://classify.oclc.org">
<response code="4"/>
<!--Classify is a product of OCLC Online Computer Library Center: http://classify.oclc.org-->
<workCount>2</workCount>
<start>0</start>
<maxRecs>25</maxRecs>
<orderBy>thold desc</orderBy>
<input type="isbn">1931498717</input>
<works>
<work author="Lakoff, George" editions="28" format="Book" holdings="1088" hyr="2014" itemtype="itemtype-book" lyr="2004" owi="796415685" schemes="DDC LCC" title="Don't think of an elephant! : know your values and frame the debate : the essential guide for progressives" wi="796415685"/>
<work author="Lakoff, George" editions="1" format="Musical score" holdings="1" hyr="2004" itemtype="itemtype-msscr" lyr="2004" owi="4735145535" schemes="DDC" title="Don't think of an elephant! : know your values and frame the debate : the essential guide for progressives" wi="4735145535"/>
</works>
</classify>
Notice there are two "work" elements. In this case, I am happy to just grab the title attribute from the first one. But even better would be to make sure it's the title of a book (format="Book") and not some other format.
Here is my macro code:
Sub ISBN()
Do
Dim xmlDoc As DOMDocument60
Set xmlDoc = New DOMDocument60
xmlDoc.async = False
xmlDoc.validateOnParse = False
r = CStr(ActiveCell.Value)
xmlDoc.Load ("http://classify.oclc.org/classify2/Classify?isbn=" + r + "&summary=true")
ActiveCell.Offset(0, 2).Value = xmlDoc.SelectSingleNode("/classify/works/work[1]").attributes.getNamedItem("title").text
ActiveCell.Offset(1, 0).Select
Loop Until IsEmpty(ActiveCell.Value)
End Sub
I get this error, "Run-time error 91 Object variable or With block variable not set," on the line that references "xmlDoc.SelectSingleNode("/classify/works/work[1]").attributes.getNamedItem("title").text"
I've tried numerous variations to try to isolate the title text but cannot get anything other than this error.
My Excel file is Microsoft Excel for Microsoft 365, on my laptop.
Help would be greatly appreciated. I am inexperienced in VBA programming and XML parsing and have been googling/reading on this for more time than I care to admit without making any progress. (There was a previous StackOverflow question on parsing ISBN XML files, but it was for a provider that no longer offers the XML files for free. That code inspired my code, but something was lost in the translation.)
Thanks tons for any help you can offer.
Your XML has a "default" namespace which applies to its contents, so when using xpath you need to create a dummy alias for that namespace and use it in your query.
See https://stackoverflow.com/a/72997440/478884
Eg:
Dim xmlDoc As DOMDocument60, col As Object, el As Object
Set xmlDoc = New DOMDocument60
xmlDoc.async = False
xmlDoc.validateOnParse = False
'set default namespace and alias "xx"
xmlDoc.SetProperty "SelectionNamespaces", _
"xmlns:xx='http://classify.oclc.org'"
xmlDoc.Load "http://classify.oclc.org/classify2/Classify?isbn=1931498717&summary=false"
Set col = xmlDoc.SelectNodes("/xx:classify/xx:works/xx:work")
'check each `work` for format and title
For Each el In col
Debug.Print "*****************"
Debug.Print el.Attributes.getNamedItem("format").Text
Debug.Print el.Attributes.getNamedItem("title").Text
Next el
I have used this code successfully to replace content in an embedded word object from excel. I copied the code for a new excel file but now it doesn't work. It opens the file but doesn't replace although I can see that it IS finding the right text and replacement text. I'm kind of lost as to what is happening.
Dim strFindText As Range
Dim strReplaceText As Range
Dim nSplitItem As Long
Set strFindText = ActiveWorkbook.Worksheets("Utilisation Form").Range("c11:c20")
Set strReplaceText = ActiveWorkbook.Worksheets("Utilisation Form").Range("a11:a20")
nSplitItem = strFindText.Count
Debug.Print strFindText.Item(0)
For Each sh In ThisWorkbook.Sheets("Utilisation Form").Shapes
If sh.Name <> "Object 1" Then sh.Delete
Next
Set urobj = ThisWorkbook.Sheets("Utilisation Form").OLEObjects("Object 1")
Set wordtemp = urobj.Duplicate
wordtemp.Verb Verb:=xlOpen
Set wordtemp2 = wordtemp.Object
For x = 1 To nSplitItem
With wordtemp2.Content.Find
.Forward = True
.Text = strFindText.Item(x)
.ClearFormatting
.Replacement.Text = strReplaceText.Item(x)
.Execute Replace:=wdReplaceAll
End With
Next x
End Sub
Thanks for the support
When the early-binding technology is used in the code you need to add a corresponding COM reference to be able to use data types. Otherwise, you need to declare everything from the Word object model as Object in the code and use the late-binding technology.
To use early binding on an object, you need to know what its v-table looks like. In Visual Basic, you can do this by adding a reference to a type library that describes the object, its interface (v-table), and all the functions that can be called on the object. Once that is done, you can declare an object as being a certain type, then set and use that object using the v-table. For example, if you wanted to Automate Microsoft Office Excel using early binding, you would add a reference to the Microsoft Excel X.0 Object Library from the Project|References dialog, and then declare your variable as being of the type Excel.Application. From then on, all calls made to your object variable would be early bound.
Read more about that in the Using early binding and late binding in Automation article.
I am trying to extract the XML information from an XFA form using VBA.
Below code works to extract the XML data to a separate file, but it requires user interaction (the user is requested to give the XML file a name). I have given up trying to automate this without user interaction due to Adobe's "safe path" requirement (which seems impossible to bypass with a VBA automation).
Dim objPDDoc As New AcroPDDoc
Dim objJSO As Object
Dim strSafePath as String
strSafePath = ""
objPDDoc.Open (FileName)
Set objJSO = objPDDoc.GetJSObject
objJSO.xfa.host.exportdata strSafePath, 0
What I would rather do is to parse the XML information directly using MSXML2.DOMDocument60. I was hoping to be able to do something like this:
Dim XMLDoc As New MSXML2.DOMDocument60
If XMLDoc.Load(objJSO.xfa.host.exportdata) = True Then
Call funcParse(XMLDoc)
End if
However, loading XMLDoc with objJSO.xfa.host.exportdata doesn't work, and I cannot seem to figure out which - if any - possibilities there are to pass the XML information using any xfa.host methods/properties.
Any help is welcome - also telling me this is not possible in VBA.
Try something like this:
myXMLstring = "<XML>BLA</XML>"
Dim xmlDoc As MSXML2.DOMDocument60
Set xmlDoc = New MSXML2.DOMDocument60
xmlDoc.LoadXML myXMLstring
See for a better example: See e.g. this post: https://desmondoshiwambo.wordpress.com/2012/07/03/how-to-load-xml-from-a-local-file-with-msxml2-domdocument-6-0-and-loadxml-using-vba/
Original poster here. After about a year of looking into this on-and-off, I found the solution.
After having accessed the JavaScript object through AccroPDDoc.GetJSObject, I can extract the nested XML as a string by using objJSO.xfa.this.saveXML.
This way, I don't have to first save the nested XML to file (which would require user interaction) - instead I can immediatly extract the nested XML and pass it to the parser.
Dim objPDDoc as New AcroPDDoc
Dim objJSO as Object
Dim XMLDoc As New MSXML2.DOMDocument60
ObjPDDoc.Open (Filename)
Set objJSO = objPDDoc.GetJSObject
If XMLDoc.LoadXML (objJSO.xfa.this.saveXML) = True then
ParseXML(XMLDoc)
End if
I`m working on a VBA macro in Excel, to gather information from a CNC program code.
So far, I have gotten Material type, thickness, x & Y sizes, and qty used.
I`m trying to get the 'cutting length' now - so I can use it in costing calculations.
Here is the XML code segment :
<Info num="6" name="Tools">
<MC machine="psys_ETN_5">
<Tool name="TN901" length="16262.96209" time="53.72817301" cutoutArea="8138.657052"/>
</MC>
</Info>
There are lots of 'Info' lines.
There may be more than one 'Tool' line, but I`m only after anything from line with 'TN901'.
The data I`m trying to capture is the value of 'Length="######.##"'
I`ve captured everything else I need from code like this :
<Material>316</Material>
<SheetX>2000</SheetX>
<SheetY>1000</SheetY>
<Thickness>3</Thickness>
</Material>
using code like this:
For Each nodemat In XMLDataDrg.SelectNodes("//Material")
Matl = nodemat.Text
Worksheets("Sheet4").Range("H" & RowA).Value = Matl
Next
For Each nodesht In XMLDataDrg.SelectNodes("//Thickness")
Thk = nodesht.Text
Worksheets("Sheet4").Range("I" & RowA).Value = Thk
Next
But that type of code does not get the cutting length.
Any help please ? :)
Thanks
Simon
Thickness is saved as XML element in your example.
The length is stored as an XML attribute.
(see https://www.xmlfiles.com/xml/xml-attributes/)
To read an XML attribute please have a look at:
Read XML Attribute VBA
Based on the code presented there you should be able to solve your issue with:
'Include a reference to Microsoft XML v3
Dim XMLDataDrg As DOMDocument30
Set XMLDataDrg = New DOMDocument30
XMLDataDrg.Load ("C:\...\sample.xml")
'...
Dim id As String
id = XMLDataDrg.SelectSingleNode("//Info/MC/Tool").Attributes.getNamedItem("length").Text
You can use an xpath to restrict to Tool elements with attribute name having value TN901 then loop all the attributes and write out. I am reading your XML from a file on desktop.
Option Explicit
Public Sub test()
Dim xmlDoc As Object
Set xmlDoc = CreateObject("MSXML2.DOMDocument")
With xmlDoc
.validateOnParse = True
.setProperty "SelectionLanguage", "XPath"
.async = False
If Not .Load("C:\Users\User\Desktop\Test.xml") Then
Err.Raise .parseError.ErrorCode, , .parseError.reason
End If
End With
Dim elem As Object, attrib As Object
For Each elem In xmlDoc.SelectNodes("//Tool[#name='TN901']")
For Each attrib In elem.Attributes
Debug.Print attrib.nodeName, attrib.Text
Next
Next
End Sub
Result:
I have a number of ActiveX controls/buttons on a page, and I would like to modify several of the parameters of the buttons (in a loop function).
I am fine with writing the loop function to achieve this, but cannot find a way to refer to the object using a string variable. I have set up an object variable (as per below), and a string variable to be used to change the reference for the object variable - but can't find a way to get it to work.
This is the code that does NOT work:
Private Sub TrialCode_Click()
Dim ButtonObj As Object
Dim ButtonCaption As String
Dim ButtonString As String
ButtonString = "CommandButton1"
Set ButtonObj = ButtonString
ButtonCaption = "Something"
ButtonObj.Caption = ButtonCaption 'example of the kind of parameters I want to change
End Sub
The Set ButtonObj = ButtonString is the command that fails, reporting a Type Mismatch error.
I'm working in Excel 2013.
I really hope there is some way to do this. Any help will be really appreciated!!!
The CommandButton belongs to an OLEObject
try
ButtonString = "CommandButton1"
Set ButtonObj = ActiveSheet.OLEObjects(ButtonString)
ButtonCaption = "Something"
ButtonObj.Object.Caption = ButtonCaption 'example of the kind of parameters I want to change
Note that some properties occur directly under ButtonObj, others such as Caption sit below Object